2012-08-06 163 views
7

背景:在服务器方面,我是一个完整的初学者,但我知道用Python编程的方式。Python服务器中的全局变量

我想安装使用基本的Python 2.7模块(SimpleHTTPServer,CGIHTTPServer等),一个简单的服务器。该服务器在启动时需要从文件加载全局只读变量,其中包含几GB的数据;然后,当每个用户访问该页面时,服务器使用大数据来生成一些输出,然后将该输出提供给用户。

例如起见,假设我有一个4 GB的文件names.txt其中包含英语的所有可能的专有名词:

Jack 
John 
Allison 
Richard 
... 

让我们假设我的目标是读名称的整个列表到内存,然后从这个大名单中随机选择一个名字。我目前能够使用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在服务器启动时立即创建为全局变量,并且每个访问只能从该变量读取?

回答

5

仅供将来参考,如果有人遇到过同样的问题:我最终分类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,他指出我的方向正确!

2

你可能想名字的值存储在一个数据库,并根据他们开始以字母存储的名称。然后,您可以随意地为a和z之间的字母做一个字母,然后再次随机再从随机起始字母中获得一个随机名称。

+1

感谢您的回答。数据库在我要学习的东西列表中,但它似乎完全是为了这个需要而矫枉过正。 – HerrKaputt 2012-08-06 14:38:20

+1

好吧,我可能会尝试生成一个随机数字,只读取文件的那一行。这样你不必循环遍历每一行。 – edhedges 2012-08-06 14:42:17

+0

这将适用于这个简单的例子。然而,它不适用于我想要的应用程序,它确实需要将整个文件读入内存。显然,这种误解不是你的错。我将编辑原始问题以反映这一点。 – HerrKaputt 2012-08-06 14:49:20

4

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

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

就个人而言,我会考虑像CherryPy作为一个简单的解决方案,IMO比BaseHTTPServer漂亮了很多。除了CherryPy以外,还有很多其他选项,比如瓶子,烧瓶,扭曲,django等等。当然,如果你需要这台服务器在其他网络服务器后面,你需要考虑设置一个反向代理或运行CherryPy as a WSGI应用程序。

+0

我实际上已经缩减为分类BaseHTTPServer。我是否正确地假设我必须重新定义BaseHTTPServer的所有方法(即,do_GET,do_POST等)?这就是为什么我认为已经存在更好的东西。 关于CherryPy,你能指点我一个“傻瓜”教程吗?我查看了他们的页面,但是甚至他们的文档,其他人都称之为“优秀”,对我来说太难理解了。 – HerrKaputt 2012-08-06 14:44:44

+0

@HerrKaputt:这些方法中的每一个都对应于您可能希望支持的HTTP方法。对于你的用例,我认为你只需要支持'do_GET'。 – stderr 2012-08-06 14:51:37

+0

非常感谢,迈克!尽管你的回答并不完全符合我的要求,但它实际上促使我进一步挖掘。我从我的问题中省略,我需要通过POST方法传递参数。我需要的是将SimpleHTTPServer子类化并创建我自己的do_POST()函数。我将从CGIHTTPServer中获得灵感。希望我不需要再提问! – HerrKaputt 2012-08-06 16:30:31

2

建立prefix tree (a.k.a. trie)一次,每次收到查询生成一个随机游走。

这应该是非常有效的。

+0

它很有效率。但它仍然不能回答我的问题:我如何将它设置为一个服务器,它构建一个由所有用户共享的只读全局变量? – HerrKaputt 2012-08-06 14:52:32

+0

@HerrKaputt然后我明显被你的例子的复杂性误导了。你宁愿要一个“hello world”的例子来设置一个基本的http服务器? – moooeeeep 2012-08-06 14:59:24

+0

类别。一个基本的HTTP服务器是我可以在Python中完成的;但是,它将无法在不同用户之间共享变量。另一方面,我能够在Python脚本中创建全局变量,但不能在不同的用户之间创建全局变量,因为(正如Mike所说),CGI为不同的用户创建独立的进程。我不知道我需要做什么来将这两件事结合起来。 – HerrKaputt 2012-08-06 15:10:18