8

背景:在服务器方面,我是一个完全的初学者,但我知道我的 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在服务器启动时立即创建为全局变量,并且每次访问仅从该变量中读取?

4

4 回答 4

6

仅供将来参考,如果有人遇到同样的问题:我最终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对于每个用户都是相同的。

感谢所有回答我问题的人,尤其是 Mike Steder,他为我指明了正确的方向!

于 2012-08-07T09:40:30.820 回答
4

CGI 通过产生一个进程来处理每个请求来工作。您需要运行一个驻留在内存中的服务器进程来处理 HTTP 请求。

您可以使用修改后的BaseHTTPServer,只需定义您自己的 Handler 类。您将在代码中加载一次数据集,然后处理程序的 do_GET 方法将随机选择一个。

就个人而言,我会研究像CherryPy这样的简单解决方案,它比 IMO 比 BaseHTTPServer 好得多。除了 CherryPy 之外,还有很多选项,例如瓶子、烧瓶、扭曲、django 等。当然,如果您需要此服务器位于其他网络服务器之后,您需要考虑设置反向代理或将CherryPy 作为 WSGI运行应用程序。

于 2012-08-06T14:36:06.177 回答
2

您可能希望将名称的值存储在 db 中,并根据名称开头的字母存储名称。然后您可以对 a 和 z 之间的字母进行随机操作,然后从那里再次随机化以从您的随机开头字母中获取随机名称。

于 2012-08-06T14:34:10.670 回答
2

构建一次前缀树(又名 trie),并在收到查询时生成随机游走。

这应该是相当有效的。

于 2012-08-06T14:40:33.590 回答