2017-02-13 3 views
0

Nehmen wir an, wir eine WSGI App haben, die auf einer ereignisgesteuerten Single-Threaded-Server gehostet wird:Eventlet wsgi Server und zeitraubende Operationen in Anfragen

from eventlet import wsgi 
import eventlet 

def app(env, start_response): 
    # IO opeartions here 
    ... 

wsgi.server(eventlet.listen(('', 8090)), app) 

Innerhalb App-Funktion, einige E/A-Operationen, als Lese-Dateien oder DB-Zugriff muss durchgeführt werden.

Wenn wir nun IO-Vorgänge in der App ausführen, wird der Server effektiv blockiert und kann keine anderen Clients bedienen.

F: Was sind mögliche Lösungen für dieses Problem? Wie kann ich erreichen, dass der Eventlet wsgi Server zeitraubende Operationen ausführt, ohne blockiert zu werden?

Antwort

0

TL; DR: Verwenden Sie mysqldb/psycopg oder eventlet.import_patched() reine Python-DB-Treiber; tpool.execute() für Dateien und alles andere.

Versuchen Sie, Ihren Gedankenprozess in Trennoperationen zu verwandeln, die in Zusammenarbeit mit Eventlet konvertiert werden können und für die es unmöglich ist. Kooperation bedeutet hier, in "Ausführungscode" - "Wartet auf Ergebnis" -Teile einzubrechen und einen Benachrichtigungsmechanismus bereitzustellen, wenn das Ergebnis bereit ist. Hauptbenachrichtigungsmechanismus für Eventlet sind Dateideskriptoren.

Also alles, was auf Dateideskriptor wartet, ist ein Kandidat, um grün zu sein (nicht blockierend). Am wichtigsten ist, dass es alle Netzwerk-IO betrifft. Wenn Ihre Blockierungsfunktion in reinem Python geschrieben ist, verwenden Sie einfach import_patched(module_name), um ihre socket und andere Verweise auf die grüne Version von Eventlet zu ändern. mysqldb und psycopg2 sind Sonderfälle von C-Erweiterungsmodulen, die dank ausdrücklicher Unterstützung ihrer Autoren kooperativ gemacht werden. Alles andere blockiert in nicht Python-Code - Ihre Option ist OS-Threads.

Leider ist das Warten auf tatsächliche Dateien voller Macken, daher empfehle ich die Verwendung von Betriebssystem-Threads und wir haben einen integrierten Thread-Pool, um das zu unterstützen. Konvertieren blocking_fun(filepath, something_else) zu eventlet.tpool.execute(blocking_fun, filepath, something_else) und es blockiert nicht alles. Weitere Informationen finden Sie in der tpool-Dokumentation.

Wenn Sie können, die gesamte Anwendung in blockierende und nicht blockierende Prozesse überarbeiten und sie über Sockets kommunizieren lassen. Das ist schwer vom Umschreiben des Code, aber sehr einfach für die Laufzeit, Debugging; robustes und ausfallsicheres Design.