Ich bin neu in Gevents und Greenlets. Ich habe eine gute Dokumentation gefunden, wie man mit ihnen arbeitet, aber keine hat mir Rechtfertigung dafür gegeben, wie und wann ich Greenlets verwenden sollte!
- Was können sie wirklich gut?
- Ist es eine gute Idee, sie auf einem Proxyserver zu verwenden oder nicht?
- Warum nicht Threads?
Ich bin mir nicht sicher, wie sie uns Parallelität bieten können, wenn sie im Grunde genommen Co-Routinen sind.
threading.Thread
ist tatsächlich ein Betriebssystem-Thread mit allen Auswirkungen. So einfach ist das also wirklich nicht. Übrigens hat Jython keine GIL AFAIK und PyPy versucht es auch loszuwerden.Antworten:
Greenlets bieten Parallelität, aber keine Parallelität. Parallelität ist, wenn Code unabhängig von anderem Code ausgeführt werden kann. Parallelität ist die gleichzeitige Ausführung von gleichzeitigem Code. Parallelität ist besonders nützlich, wenn im Benutzerbereich viel Arbeit zu erledigen ist, und das ist normalerweise CPU-lastiges Zeug. Parallelität ist nützlich, um Probleme zu lösen und verschiedene Teile parallel zu planen und einfacher zu verwalten.
Greenlets glänzen wirklich in der Netzwerkprogrammierung, bei der Interaktionen mit einem Socket unabhängig von Interaktionen mit anderen Sockets auftreten können. Dies ist ein klassisches Beispiel für Parallelität. Da jedes Greenlet in einem eigenen Kontext ausgeführt wird, können Sie weiterhin synchrone APIs ohne Threading verwenden. Dies ist gut, da Threads in Bezug auf den virtuellen Speicher und den Kernel-Overhead sehr teuer sind, sodass die Parallelität, die Sie mit Threads erzielen können, erheblich geringer ist. Darüber hinaus ist das Threading in Python aufgrund der GIL teurer und eingeschränkter als gewöhnlich. Alternativen zur Parallelität sind normalerweise Projekte wie Twisted, libevent, libuv, node.js usw., bei denen Ihr gesamter Code denselben Ausführungskontext verwendet, und die Registrierung von Ereignishandlern.
Es ist eine hervorragende Idee, Greenlets (mit entsprechender Netzwerkunterstützung, z. B. über gevent) zum Schreiben eines Proxys zu verwenden, da Ihre Bearbeitung von Anforderungen unabhängig ausgeführt werden kann und als solche geschrieben werden sollte.
Greenlets bieten Parallelität aus den Gründen, die ich zuvor angegeben habe. Parallelität ist keine Parallelität. Durch das Verbergen der Ereignisregistrierung und das Durchführen einer Zeitplanung für Anrufe, die normalerweise den aktuellen Thread blockieren würden, stellen Projekte wie gevent diese Parallelität offen, ohne dass eine Änderung an einer asynchronen API erforderlich ist, und dies zu erheblich geringeren Kosten für Ihr System.
quelle
Wenn Sie die Antwort von @ Max nehmen und sie für die Skalierung relevant machen, können Sie den Unterschied erkennen. Dies habe ich erreicht, indem ich die zu füllenden URLs wie folgt geändert habe:
Ich musste die Multiprozess-Version fallen lassen, als sie fiel, bevor ich 500 hatte; aber bei 10.000 Iterationen:
Sie sehen also, dass es bei der Verwendung von gevent einen signifikanten Unterschied bei der E / A gibt
quelle
Wenn Sie die Antwort von @TemporalBeing oben korrigieren, sind Greenlets nicht "schneller" als Threads und es ist eine falsche Programmiertechnik, 60000 Threads zu erzeugen , um ein Parallelitätsproblem zu lösen. Stattdessen ist ein kleiner Pool von Threads angemessen. Hier ist ein vernünftigerer Vergleich (aus meinem reddit-Beitrag als Antwort auf Leute, die diesen SO-Beitrag zitieren).
Hier sind einige Ergebnisse:
Das Missverständnis, das jeder über nicht blockierende E / A mit Python hat, ist die Überzeugung, dass der Python-Interpreter die Arbeit erledigen kann, Ergebnisse von Sockets in großem Maßstab schneller abzurufen, als die Netzwerkverbindungen selbst E / A zurückgeben können. Während dies in einigen Fällen sicherlich zutrifft, trifft es bei weitem nicht so oft zu, wie die Leute denken, da der Python-Interpreter sehr, sehr langsam ist. In meinem Blog-Beitrag hier illustriere ich einige grafische Profile, die zeigen, dass selbst für sehr einfache Dinge, wenn Sie mit einem klaren und schnellen Netzwerkzugriff auf Datenbanken oder DNS-Server zu tun haben, diese Dienste viel schneller als der Python-Code zurückkehren können kann sich um viele tausend dieser Verbindungen kümmern.
quelle
Das ist interessant genug, um es zu analysieren. Hier ist ein Code zum Vergleichen der Leistung von Greenlets im Vergleich zum Multiprocessing-Pool im Vergleich zum Multithreading:
Hier sind die Ergebnisse:
Ich denke, dass Greenlet behauptet, dass es im Gegensatz zur Multithreading-Bibliothek nicht an GIL gebunden ist. Darüber hinaus sagt Greenlet doc, dass es für den Netzwerkbetrieb gedacht ist. Für einen netzwerkintensiven Betrieb ist das Thread-Switching in Ordnung und Sie können sehen, dass der Multithreading-Ansatz ziemlich schnell ist. Außerdem ist es immer vorzuziehen, die offiziellen Bibliotheken von Python zu verwenden. Ich habe versucht, Greenlet unter Windows zu installieren, und bin auf ein DLL-Abhängigkeitsproblem gestoßen. Daher habe ich diesen Test unter Linux VM ausgeführt. Versuchen Sie immer, einen Code zu schreiben, in der Hoffnung, dass er auf jedem Computer ausgeführt wird.
quelle
getsockbyname
die Ergebnisse auf Betriebssystemebene zwischengespeichert werden (zumindest auf meinem Computer). Wenn es auf einem zuvor unbekannten oder abgelaufenen DNS aufgerufen wird, führt es tatsächlich eine Netzwerkabfrage durch, die einige Zeit dauern kann. Wenn ein Hostname aufgerufen wird, der erst kürzlich aufgelöst wurde, wird die Antwort viel schneller zurückgegeben. Folglich ist Ihre Messmethode hier fehlerhaft. Dies erklärt Ihre seltsamen Ergebnisse - Gevent kann nicht viel schlimmer sein als Multithreading - beide sind auf VM-Ebene nicht wirklich parallel.using_gevent() 421.442985535ms using_multiprocessing() 394.540071487ms using_multithreading() 402.48298645ms