背景:在服务器方面,我是一个完全的初学者,但我知道我用Python编程的方式。
我正在尝试使用基本的Python 2.7模块(SimpleHTTPServer,CGIHTTPServer等)设置一个简单的服务器。此服务器在启动时需要从文件中加载包含几 GB 数据的全局只读变量;然后,当每个用户访问页面时,服务器使用大数据生成一些输出,然后将其提供给用户。
举个例子,假设我有一个 4 GB 的文件names.txt
其中包含所有可能的英语专有名词:
Jack
John
Allison
Richard
...
假设我的目标是将整个名称列表读入内存,然后从这个大的专有名词列表中随机选择 1 个名称。我目前能够使用Python的本机CGIHTTPServer模块来完成此操作。首先,我只需通过终端执行直接运行 CGIHTTPServer 模块:
python -m CGIHTTPServer
然后,有人访问www.example-server.net:8000/foo.py
并随机为他们提供这些名称之一。我在foo.py
有以下代码:
#!/usr/bin/env python
import random
name_list = list()
FILE = open('names.txt','r')
for line in FILE:
name = line[:-1]
name_list.append(name)
FILE.close()
name_to_return = random.choice(name_list)
print "Content-type: text/html"
print
print "<title>Here is your name</title>"
print "<p>" + name_to_return + "</p>"
这符合我的需求;但是,它的效率极低,因为每次访问都会强制服务器重新读取 4 GB 的文件。
我怎样才能把它变成一个有效的过程,其中变量name_list
在服务器启动时立即创建为全局,并且每次访问仅从该变量读取?
仅供将来参考,如果有人遇到同样的问题:我最终对CGIHTTPServer
的请求处理程序进行了子类化并实现了一个新的do_POST()
函数。如果你有一个没有全局变量的工作CGI脚本,像这样的东西应该可以帮助你开始:
import CGIHTTPServer
import random
import sys
import cgi
class MyRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
global super_important_list
super_important_list = range(10)
random.shuffle(super_important_list)
def do_POST(s):
"""Respond to a POST request."""
form = cgi.FieldStorage(fp=s.rfile,headers=s.headers,environ={'REQUEST_METHOD':'POST','CONTENT_TYPE':s.headers['Content-Type'],})
s.wfile.write("<html><head><title>Title goes here.</title></head>")
s.wfile.write("<body><p>This is a test.</p>")
s.wfile.write("<p>You accessed path: %s</p>" % s.path)
s.wfile.write("<p>Also, super_important_list is:</p>")
s.wfile.write(str(super_important_list))
s.wfile.write("<p>Furthermore, you POSTed the following info: ")
for item in form.keys():
s.wfile.write("<p>Item: " + item)
s.wfile.write("<p>Value: " + form[item].value)
s.wfile.write("</body></html>")
if __name__ == '__main__':
server_address = ('', 8000)
httpd = CGIHTTPServer.BaseHTTPServer.HTTPServer(server_address, MyRequestHandler)
try:
httpd.serve_forever()
except KeyboardInterrupt:
sys.exit()
每当有人填写您的表单并执行 POST 时,变量form
将是一个类似字典的对象,其键值对可能因您网站的每个用户而异,但全局变量super_important_list
对于每个用户都是相同的。
感谢所有回答我问题的人,尤其是迈克·斯特德,他为我指明了正确的方向!
CGI通过生成一个进程来处理每个请求来工作。 您需要运行一个保留在内存中的服务器进程来处理 HTTP 请求。
您可以使用修改后的 BaseHTTPServer,只需定义自己的 Handler 类即可。 您将在代码中加载数据集一次,然后处理程序的do_GET方法将随机选择一个。
就个人而言,我会将CherryPy之类的东西视为一个简单的解决方案,IMO比BaseHTTPServer好得多。 除了CherryPy之外,还有很多选择,如瓶子,烧瓶,扭曲,姜戈等。 当然,如果您需要此服务器位于其他Web服务器后面,则需要考虑设置反向代理或将CherryPy作为WSGI应用程序运行。
您可能希望将名称的值存储在数据库中,并根据名称开头的字母存储名称。然后,您可以对a和z之间的字母进行随机处理,然后从那里再次随机化,以从随机的开始字母中获取一个随机名称。
构建一次前缀树(又名trie),并在收到查询时生成随机漫游。
这应该非常有效。