2012-08-06 11 views
7

Contesto: Sono un principiante assoluto quando si tratta di server, ma conosco il mio modo di programmare in Python.Variabile globale nel server Python

Sto provando a configurare un server semplice utilizzando i moduli base Python 2.7 (SimpleHTTPServer, CGIHTTerver, ecc.). Questo server deve caricare una variabile globale di sola lettura con diversi GB di dati da un file all'avvio; quindi, quando ogni utente accede alla pagina, il server utilizza i big data per generare un output che viene poi dato all'utente.

Per motivi di esempio, supponiamo Ho un file da 4 GB names.txt che contiene tutte le possibili nomi propri della lingua inglese:

Jack 
John 
Allison 
Richard 
... 

Supponiamo che il mio obiettivo è quello di leggere l'intero elenco di nomi in memoria , quindi scegli 1 nome a caso da questa grande lista di nomi propri. Attualmente sono in grado di utilizzare il modulo CGIHTTPServer nativo di Python per realizzare questo. Per iniziare, ho appena eseguito il modulo CGIHTTPServer direttamente, eseguendo da terminale:

python -m CGIHTTPServer 

Poi, qualcuno accessi www.example-server.net:8000/foo.py e si sono date uno di questi nomi a caso. Ho il seguente codice nel 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>" 

Questo fa quello che voglio; tuttavia, è estremamente inefficiente, poiché ogni accesso obbliga il server a rileggere un file da 4 GB.

Come posso rendere questo in un processo efficiente, in cui la variabile name_list viene creata come globale immediatamente all'avvio del server e ogni accesso legge solo da tale variabile?

risposta

5

Solo per riferimento futuro, se qualcuno dovesse mai affrontare lo stesso problema: ho finito per sottoclasse il gestore di richieste CGIHTTPServer e l'implementazione di una nuova funzione do_POST().Se tu avessi uno script CGI di lavoro senza le variabili globali, qualcosa di simile dovrebbe iniziare:

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() 

Ogni volta che qualcuno compila il modulo ed esegue un POST, la variabile form sarà un oggetto simil dizionario con chiave- coppie di valori che possono differire per ogni utente del sito, ma la variabile globale super_important_list sarà la stessa per ogni utente.

Grazie a tutti coloro che hanno risposto alla mia domanda, in particolare Mike Steder, che mi ha indicato nella giusta direzione!

2

Si consiglia di memorizzare i valori dei nomi in un db e di memorizzare i nomi in base alla lettera con cui iniziano. Quindi puoi fare un casuale per una lettera tra aez e da lì randomize di nuovo per ottenere un nome casuale dalla tua lettera iniziale casuale.

+1

Grazie per la risposta. I database sono nel mio elenco di cose da imparare, ma sembra un completo overkill solo per questa necessità. – HerrKaputt

+1

Okay allora proverei a generare un numero casuale e leggerò solo quella riga del file. In questo modo non è necessario scorrere ogni riga. – edhedges

+0

Ciò funzionerebbe per questo semplice esempio. Tuttavia, non funzionerebbe per l'applicazione che ho in mente, che richiede veramente la lettura dell'intero file in memoria. Ovviamente, questo malinteso non è colpa tua. Modificherò la domanda originale per riflettere questo. – HerrKaputt

4

CGI funziona creando un processo per gestire ogni richiesta. È necessario eseguire un processo del server che rimane in memoria gestisce le richieste HTTP.

È possibile utilizzare uno BaseHTTPServer modificato, basta definire la propria classe Handler. Caricheresti il ​​set di dati una volta nel tuo codice e quindi il metodo do_GET del tuo gestore ne sceglierebbe uno a caso.

Personalmente, guarderei qualcosa come CherryPy come una soluzione semplice che è molto più bella di BaseHTTerver. Ci sono tantissime altre opzioni oltre a CherryPy come flacone, flacone, twisted, django, ecc. Ovviamente se hai bisogno che questo server sia dietro ad altri server web, devi cercare di configurare un proxy inverso o eseguire l'app CherryPy as a WSGI.

+0

Mi sono effettivamente ridimensionato in BaseHTTerver sottoclassing. Sono corretto nel presupponendo che devo ridefinire TUTTI i metodi di BaseHTTerver (cioè, do_GET, do_POST, ecc.)? Questo è il motivo per cui ho pensato che esistesse già qualcosa di meglio. Per quanto riguarda CherryPy, puoi indicarmi un tutorial "for dummies"? Ho esaminato la loro pagina ma anche la loro documentazione, che altri descrivono come "eccellente", è troppo difficile da capire per me. – HerrKaputt

+0

@HerrKaputt: ognuno di questi metodi corrisponde a un metodo HTTP che * potresti * voler supportare. Per il tuo caso di utilizzo, penso che tu debba solo supportare 'do_GET'. – stderr

+0

Grazie mille, Mike! Mentre la tua risposta non è esattamente quello che sto cercando, in realtà mi ha spinto a scavare ulteriormente. Ho omesso dalla mia domanda che ho bisogno di passare i parametri attraverso i metodi POST. Ciò di cui ho bisogno, quindi, è di sottoclare SimpleHTTerver e creare la mia funzione do_POST(). Prenderò ispirazione da quello in CGIHTTerver. Spero di non aver bisogno di fare ulteriori domande! – HerrKaputt

2

Creare una prefix tree (a.k.a. trie) una volta e generare una passeggiata casuale ogni volta che si riceve una query.

Questo dovrebbe essere abbastanza efficiente.

+0

È efficiente. Ma continua a non rispondere alla mia domanda: come faccio a configurarlo come un server che crea una variabile di sola lettura globale che è condivisa da tutti gli utenti? – HerrKaputt

+0

@HerrKaputt Quindi ovviamente sono stato indotto dalla complessità del tuo esempio. Preferisci un esempio di "ciao mondo" per configurare un server http di base? – moooeeeep

+0

Sort of. Un server HTTP di base è qualcosa che posso fare in Python; tuttavia, non sarà in grado di condividere le variabili tra diversi utenti. D'altra parte, sono in grado di creare variabili globali in uno script Python, ma non tra utenti diversi, perché (come diceva Mike) CGI crea processi indipendenti per utenti diversi. Non so cosa devo fare per combinare queste due cose. – HerrKaputt