2012-09-29 6 views
8

Ich habe ein Gewinde (Python mit threads) HTTP-Server, indem eine Klasse eingerichtet, die von erbt Http und ThreadingMixIn:Verarbeitung Simultaneous/asynchrone Anforderungen mit Python BaseHTTPServer

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): 
    pass 

I eine Handler-Klasse habe, die erben von BaseHTTPRequestHandler und starte ich den Server mit so etwas wie folgt aus:

class MyHandler(BaseHTTPRequestHandler): 
    ... 

server = ThreadedHTTPServer(('localhost', 8080), MyHandler) 
# Prevent issues with socket reuse 
server.allow_reuse_address = True 
# Start the server 
server.serve_forever() 

das alles ist ziemlich einfach. Das Problem, auf das ich stoße, ist, dass ThreadingMixIn, ForkingMixIn oder andere die Anfrage blockieren, damit der Request-Handler zurückkehrt. Dies kann leicht durch die Umsetzung dieses Beispielcode zu sehen:

class MyHandler(BaseHTTPRequestHandler): 
    def respond(self, status_code): 
     self.send_response(status_code) 
     self.end_headers() 

    def do_GET(self): 
     print "Entered GET request handler" 
     time.sleep(10) 
     print "Sending response!" 
     respond(200) 

Wenn der Server diese gleichzeitig verarbeiten würde, dann würden wir in der Lage sein, zwei Anforderungen zu senden und den Server sehen Geben Sie beide Request-Handler, bevor entweder Antwort zu senden. Stattdessen gibt der Server den GET-Request-Handler für die erste Anfrage ein, wartet darauf, dass er zurückkehrt und gibt ihn dann für die zweite Anfrage ein (die zweite Anfrage benötigt also ~ 20 Sekunden anstatt 10 zurück zu geben).

Gibt es eine einfache Möglichkeit für mich, ein System zu implementieren, bei dem der Server nicht auf die Rückgabe wartet? Genauer gesagt versuche ich ein System zu schreiben, das darauf wartet, mehrere Anfragen zu empfangen, bevor es einen von ihnen zurückgibt (eine Form von langem Polling) und Probleme aufzeigt, bei denen die erste Anfrage wartet, dass zukünftige Anfragen keine Verbindung zum Server herstellen.

Antwort

11
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): 
    pass 

ist genug. Ihr Client führt wahrscheinlich keine gleichzeitigen Anfragen durch. Wenn Sie die Anforderungen parallel ausführen, funktioniert der Thread-Server wie erwartet. Hier ist der Kunde:

#!/usr/bin/env python 
import sys 
import urllib2 

from threading import Thread 

def make_request(url): 
    print urllib2.urlopen(url).read() 

def main(): 
    port = int(sys.argv[1]) if len(sys.argv) > 1 else 8000 
    for _ in range(10): 
     Thread(target=make_request, args=("http://localhost:%d" % port,)).start() 

main() 

und der entsprechende Server:

import time 
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer, test as _test 
from SocketServer  import ThreadingMixIn 


class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): 
    pass 

class SlowHandler(BaseHTTPRequestHandler): 
    def do_GET(self): 
     self.send_response(200) 
     self.send_header("Content-type", "text/plain") 
     self.end_headers() 

     self.wfile.write("Entered GET request handler") 
     time.sleep(1) 
     self.wfile.write("Sending response!") 

def test(HandlerClass = SlowHandler, 
     ServerClass = ThreadedHTTPServer): 
    _test(HandlerClass, ServerClass) 


if __name__ == '__main__': 
    test() 

Alle 10 Anfragen in 1 Sekunde zu beenden. Wenn Sie ThreadingMixIn aus der Serverdefinition entfernen, benötigen alle 10 Anfragen 10 Sekunden.

+2

Ich habe dies getestet, indem ich Anfragen über Google Chrome an den Server gesendet habe. Es stellte sich heraus, dass Chrome meine Anfragen an denselben Server serialisierte und darauf wartete, dass einer zurückkehrte, bevor der nächste gesendet wurde. Durch Ausführen eines einfachen Python-Skripts wurde das Problem behoben. Vielen Dank! – Dylnuge

+0

Aus meiner Erfahrung zeigt time.sleep (1) nicht die tatsächliche Arbeitslast von 1 Sekunde an, also denke ich nicht, dass Sie die Latenz mit thread.sleep testen sollten. Bedauerlicherweise habe ich nicht die formelle Erklärung, aber ich vermute, dass es etwas mit der Optimierung der gemeinsamen Nutzung von Ressourcen im Falle von thread.sleep zu tun hat. – MikeL

+0

@MikeL: 'time.sleep (1)' ist für den Fall in der Antwort geeignet. Uns interessiert nur, ob der Server mehrere gleichzeitige Anfragen überhaupt verarbeiten kann. Wie OP sagte: Das Problem war, dass der Browser nicht mehr als eine Anfrage an dieselbe URL stellt. – jfs