2012-08-06 110 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