Eine saubere, leichte Alternative zu Pythons verdrehtem? [geschlossen]

222

Vor (langer) Zeit habe ich einen Web-Spider geschrieben, den ich multithreaded habe, damit gleichzeitig Anfragen auftreten können. Das war in meiner Python-Jugend, in den Tagen, bevor ich über die GIL und die damit verbundenen Probleme für Multithread-Code Bescheid wusste (IE, die meisten Dinge werden nur serialisiert!) ...

Ich möchte diesen Code überarbeiten, um ihn robuster und leistungsfähiger zu machen. Grundsätzlich gibt es zwei Möglichkeiten, dies zu tun: Ich könnte das neue Multiprocessing-Modul in 2.6+ verwenden oder mich für ein reaktor- / ereignisbasiertes Modell entscheiden. Ich würde das lieber später machen, da es viel einfacher und weniger fehleranfällig ist.

Die Frage bezieht sich also darauf, welcher Rahmen am besten zu meinen Bedürfnissen passt. Das Folgende ist eine Liste der Optionen, die ich bisher kenne:

  • Twisted : Der Urvater der Python-Reaktor-Frameworks: scheint jedoch komplex und etwas aufgebläht zu sein. Steile Lernkurve für eine kleine Aufgabe.
  • Eventlet : Von den Jungs von Lindenlab . Greenlet-basiertes Framework, das auf diese Art von Aufgaben ausgerichtet ist. Ich habe mir den Code angesehen und er ist nicht allzu hübsch: Nicht pep8-konform, mit Drucken übersät (warum machen die Leute das in einem Framework!?), Scheint die API ein wenig inkonsistent zu sein.
  • PyEv : Unreif , scheint momentan niemand zu sein, der es benutzt, obwohl es auf libevent basiert, also hat es ein solides Backend.
  • asyncore : Aus der stdlib: über low-level, scheint eine Menge Beinarbeit zu sein, nur um etwas in Gang zu bringen.
  • tornado : Obwohl dies ein serverorientiertes Produkt ist, das für die Serverung dynamischer Websites entwickelt wurde, verfügt es über einen asynchronen HTTP-Client und einen einfachen ioloop . Sieht so aus, als könnte es die Arbeit erledigen, aber nicht das, wofür es gedacht war. [edit: läuft leider nicht unter Windows, was für mich zählt - es ist eine Voraussetzung für mich, diese lahme Plattform zu unterstützen]

Gibt es etwas, das ich überhaupt vermisst habe? Sicherlich muss es da draußen eine Bibliothek geben, die zum Sweet Spot einer vereinfachten asynchronen Netzwerkbibliothek passt!

[edit: Vielen Dank an intgr für seinen Zeiger auf diese Seite . Wenn Sie nach unten scrollen, werden Sie sehen, dass es eine wirklich schöne Liste von Projekten gibt, die darauf abzielen, diese Aufgabe auf die eine oder andere Weise anzugehen. Es scheint tatsächlich, dass sich die Dinge seit der Einführung von Twisted tatsächlich weiterentwickelt haben: Die Menschen scheinen nun eine auf Co-Routine basierende Lösung gegenüber einer herkömmlichen reaktor- / rückruforientierten Lösung zu bevorzugen . Die Vorteile dieses Ansatzes sind klarer, direkterer Code: Ich habe ihn sicherlich in der Vergangenheit gefunden, insbesondere bei der Arbeit mit boost.asioIn C ++ kann dieser auf Rückrufen basierende Code zu Designs führen, die schwer zu verfolgen sind und für das ungeübte Auge relativ dunkel sind. Durch die Verwendung von Co-Routinen können Sie Code schreiben, der zumindest etwas synchroner aussieht. Ich denke, jetzt ist es meine Aufgabe, herauszufinden, welche dieser vielen Bibliotheken mir gefällt, und es auszuprobieren! Ich bin froh, dass ich jetzt gefragt habe ...]

[Bearbeiten: Vielleicht von Interesse für jeden, der diese Frage verfolgt oder über sie gestolpert ist oder sich in irgendeiner Weise um dieses Thema kümmert: Ich habe eine wirklich gute Zusammenfassung des aktuellen Status der verfügbaren Tools für diesen Job gefunden]

jkp
quelle
14
Python ist Multithread-fähig und erlaubt nur nicht, dass zwei Threads gleichzeitig Python-Code ausführen.
Intgr
86
Ich habe aus Ihrer Frage viel mehr gelernt als aus Antworten darauf.
Denis Otkidach
2
@Denis: heh, danke ich denke! Es gab auch einige gute Hinweise in den Antworten, insbesondere intgr. Ich wusste über viele Optionen Bescheid und wollte nicht nur, dass die Antworten mit diesen gepackt sind, also dachte ich, ich würde mir die Mühe machen, das zu
formulieren
5
> Die Leute scheinen jetzt eher eine auf Co-Routine basierende Lösung als eine herkömmliche reaktor- / rückruforientierte zu bevorzugen. Dies ist kein vernünftiger Vergleich. "co-routinemäßige Lösungen" und "reaktororientierte" Lösungen sind orthogonal. (Ignorieren Sie die Tatsache, dass Python keine Coroutinen hat.) Sehen Sie sich Twisted's inlineCallbacks an, um zu sehen, wie Sie den Programmierstil, den Sie zu bevorzugen scheinen, mit einer robusten, ausgereiften Netzwerkschicht erzielen können, die Sie keinen komplexen Plattform-Besonderheiten aussetzt.
Jean-Paul Calderone
2
Einige Punkte, die Sie hinzufügen sollten: 1. Tornado läuft unter Windows sehr gut. Es ist einfach nicht so performant und skalierbar, da es selectfür das E / A-Multiplexing verwendet wird. Aber Sie sollten in der Lage sein, mit Tornado-Pyuv eine anständige Leistung zu erzielen . 2. In Python 3.3+ und seinem Backport- Trollius gibt es jetzt Asyncio , mit dem jede Tornado-Anwendung in ihrer Ereignisschleife ausgeführt werden kann (Twisted wird bald unterstützt).
Schlamar

Antworten:

28

Ich mochte das Concurrence- Python-Modul, das entweder Stackless Python-Mikrothreads oder Greenlets für leichtes Threading verwendet. Alle blockierenden Netzwerk-E / A werden transparent über eine einzige libeventSchleife asynchronisiert , sodass sie fast so effizient sein sollten wie ein echter asynchroner Server.

Ich nehme an, es ist Eventlet auf diese Weise ähnlich.

Der Nachteil ist, dass sich die API stark von Pythons sockets/ threadingModulen unterscheidet. Sie müssen ein gutes Stück Ihrer Anwendung neu schreiben (oder eine Kompatibilitäts-Shim-Ebene schreiben).

Bearbeiten: Es scheint, dass es auch Cogen gibt , das ähnlich ist, aber anstelle von Greenlets die erweiterten Generatoren von Python 2.5 für seine Coroutinen verwendet. Dies macht es portabler als Concurrence und andere Alternativen. Netzwerk-E / A erfolgt direkt mit epoll / kqueue / iocp.

intgr
quelle
@intgr: tolle Links. Ich hatte beide schon einmal gesehen, das sind die Dinge, von denen ich gehofft hatte, dass sie herausgespült werden. +1
jkp
3
Es sieht so aus, als wäre Concurrence ein totes Projekt, da es sich um das letzte Update vor vier Jahren handelt.
Gewthen
Projekt ist tot, Hyves auch!
Bahadir Cambel
1
Seit Python 2.5 ist viel passiert. Asyncio in Python 3.5 ist großartig.
Joseph Sheedy
99

Twisted ist komplex, da haben Sie Recht. Verdreht ist nicht aufgebläht.

Wenn Sie hier einen Blick darauf werfen: http://twistedmatrix.com/trac/browser/trunk/twisted finden Sie eine organisierte, umfassende und sehr gut getestete Suite mit vielen Protokollen des Internets sowie Hilfecode zum Schreiben und sehr ausgefeilte Netzwerkanwendungen bereitstellen. Ich würde Aufblähen nicht mit Vollständigkeit verwechseln.

Es ist bekannt, dass die Twisted-Dokumentation auf den ersten Blick nicht besonders benutzerfreundlich ist, und ich glaube, dass dies eine unglückliche Anzahl von Menschen abweist. Aber Twisted ist erstaunlich (IMHO), wenn Sie die Zeit investieren. Ich habe es getan und es hat sich gelohnt, und ich würde anderen empfehlen, dasselbe zu versuchen.

Clemesha
quelle
4
@clemesha: Vielleicht hast du recht und es ist nicht aufgebläht, aber es fühlt sich so an, als ob es ein bisschen zu viel gibt, um meinen Kopf dazu zu bringen, etwas Einfaches zu tun. Ich verstehe asynchrone Programmierung, ich habe in C ++ mit boost :: asio gearbeitet, daher sind die Konzepte nicht neu, aber es ist alles, was mit verdrehten Sachen zu tun hat: Es ist eine ganz neue Welt, ähnlich wie Django für Web-Sachen. Wenn ich wieder Web-Sachen mache, arbeite ich mit leichtem WSGI-Code und stecke nur das zusammen, was ich brauche. Pferde für Kurse, denke ich.
jkp
7
@clemesha: ähm, ich habe heute den Sprung gewagt, um einen Blick darauf zu werfen: Twisted wiegt 20 MB! Sogar der Kern ist 12 MB ... wenn das nicht aufgebläht ist, bin ich mir nicht ganz sicher, was es ist.
JKP
29
Die grundlegenden Twisted-APIs sind ziemlich klein (Reaktor, verzögert, Protokoll). Der größte Teil des Twisted-Codes besteht aus asynchronen Protokollimplementierungen, die diese Grundlagen verwenden. "Aufblähen" ist hier (oder in den meisten Fällen) kein nützliches Adjektiv. Die Größe von Twisted ist angemessen für die Menge an Sachen, die es macht.
daf
56

gevent ist eventlet aufgeräumt .

API-weise folgt es den gleichen Konventionen wie die Standardbibliothek (insbesondere Threading- und Multiprocessing-Module), wo es sinnvoll ist. Sie haben also vertraute Dinge wie Warteschlange und Ereignis , mit denen Sie arbeiten können.

Es unterstützt nur libevent ( Update: libev seit 1.0 ) als Reaktorimplementierung, nutzt es jedoch voll aus. Es verfügt über einen schnellen WSGI-Server, der auf libevent-http basiert und DNS-Abfragen über libevent-dns löst, anstatt wie die meisten anderen Bibliotheken einen Thread-Pool zu verwenden machen. ( Update: Da 1.0 c-ares verwendet wird, um asynchrone DNS-Abfragen durchzuführen, ist Threadpool ebenfalls eine Option.)

Wie bei einem Eventlet werden die Rückrufe und Zurückstellungen durch die Verwendung von Greenlets unnötig .

Schauen Sie sich die Beispiele an: gleichzeitiges Herunterladen mehrerer URLs , langes Abrufen von Webchat .

Denis Bilenko
quelle
4
Ich werde Gevent zum zweiten Mal - Nachdem ich viele der Lösungen überprüft habe, hat Gevent für mich sehr gut funktioniert. Es erlaubte mir, den größten Teil meines bestehenden Programms beizubehalten, und die erforderlichen Änderungen waren trivial - das Beste ist, wenn der Code in 3, 4, 5, ... Jahren gepflegt werden muss, macht er es immer noch Sinn für alle, die nicht mit gevent vertraut sind, der größte Showstopper für Twisted ist die starke Lernkurve. Dies verursacht Probleme nicht nur bei der Implementierung, sondern auch später während der Wartung ...
Martin Tournoij
27

Einen wirklich interessanten Vergleich solcher Frameworks hat Nicholas Piël in seinem Blog zusammengestellt: Es ist eine Lektüre wert!

jkp
quelle
2
Obwohl ich der Meinung bin, dass der Artikel eine interessante Lektüre war, halte ich es für sinnvoll, die Gültigkeit der vorgestellten Benchmarks zu prüfen. Siehe die Kommentare hier: reddit.com/r/programming/comments/ahepg/…
Clemesha
1
@clemesha, während der Punkt auf dieser reddit-Seite erwähnenswert ist, wurde der Benchmark auf einem Dual-Core-Computer durchgeführt und litt wahrscheinlich nicht unter dem beschriebenen schwerwiegenden Fehler. Ich nehme an, es ist möglich, dass sowohl der Client als auch der Server auf demselben Kern ausgeführt wurden, aber es scheint nicht wahrscheinlich.
Peter Hansen
15

Keine dieser Lösungen wird die Tatsache vermeiden, dass die GIL die CPU-Parallelität verhindert - sie sind nur bessere Möglichkeiten, um E / A-Parallelität zu erhalten, die Sie bereits mit Threads haben. Wenn Sie der Meinung sind, dass Sie eine bessere E / A-Leistung erzielen können, verfolgen Sie auf jeden Fall eine dieser Möglichkeiten. Wenn Ihr Engpass jedoch bei der Verarbeitung der Ergebnisse liegt, hilft hier nichts außer dem Multiprozessor-Modul.

Adam Hupp
quelle
Was ist falsch daran, mehrere Prozesse zu verwenden?
Emil Ivanov
3
Gar nichts, daher der Vorschlag, das Multiprozessor-Modul zu verwenden.
Adam Hupp
11

Ich würde nicht so weit gehen, Twisted als aufgebläht zu bezeichnen, aber es ist schwierig, den Kopf herumzureißen. Ich habe es eine ganze Weile vermieden, mich wirklich auf ein Lernen einzulassen, da ich immer etwas Leichteres für 'kleine Aufgaben' wollte.

Jetzt, da ich noch mehr damit gearbeitet habe, muss ich sagen, dass es SEHR schön ist, alle Batterien im Lieferumfang zu haben.

Alle anderen asynchronen Bibliotheken, mit denen ich gearbeitet habe, sind viel weniger ausgereift, als sie überhaupt erscheinen. Die Ereignisschleife von Twisted ist solide.

Ich bin mir nicht ganz sicher, wie ich die steile Twisted-Lernkurve lösen soll. Es könnte hilfreich sein, wenn jemand es gabelt und ein paar Dinge aufräumt, wie das Entfernen aller Abwärtskompatibilitäts-Cruft und der toten Projekte. Aber das ist die Natur ausgereifter Software, denke ich.

Rhettg
quelle
Wenn Sie jemals nachgeschlagen hätten, wie der GTK-Reaktor unter Windows implementiert ist (Hardcore-Abfrage alle 10 ms : twistedmatrix.com/trac/browser/trunk/twisted/internet/… ), würden Sie das nicht als "ausgereift" bezeichnen ...
schlamar
2
Hallo @schlamar. Dieser böse Hack wurde als Problemumgehung für einige ziemlich schwerwiegende Fehler in GTK + implementiert, damals, als es viel weniger Bedenken hinsichtlich der Energieeffizienz gab :). Das Schöne an Twisted ist jedoch, dass wir diesen Fehler einmal haben , ihn im Framework beheben können und unsere Benutzer sich darüber keine Sorgen machen müssen. Möchten Sie einen Fix beisteuern, der dieses Problem behebt und beseitigt (veraltet und später entfernt) PortableGtkReactor?
Glyphe
1
@Glyph Ich habe hilfreiche Ratschläge zu twistedmatrix.com/trac/ticket/4744#comment:2 hinzugefügt, wenn jemand anderes dieses Problem angehen möchte, da einige dieser Probleme noch bestehen. Übrigens hätten Sie dies viel effizienter lösen können, indem Sie Rückrufe zwischen den beiden Ereignisschleifen geplant hätten.
schlamar
7

Kamaelia wurde noch nicht erwähnt. Das Parallelitätsmodell basiert auf der Verkabelung von Komponenten mit Nachrichten, die zwischen Posteingängen und Postausgängen übertragen werden. Hier ist eine kurze Übersicht.

Steven Kryskalla
quelle
5
Ich habe Kamaelia für eine App verwendet - es war extrem schmerzhaft. IMHO gibt es andere, bessere Optionen für Concurrenct in Python (von denen die meisten oben erwähnt sind)
Ben Ford
7

Ich habe angefangen, Twisted für einige Dinge zu verwenden. Das Schöne daran ist fast, dass es "aufgebläht" ist. Es gibt Anschlüsse für nahezu jedes der Hauptprotokolle. Sie können einen Jabber-Bot haben, der Befehle entgegennimmt und auf einem IRC-Server veröffentlicht, per E-Mail an jemanden sendet, einen Befehl ausführt, von einem NNTP-Server liest und eine Webseite auf Änderungen überwacht. Die schlechte Nachricht ist, dass es all das kann und die Dinge für einfache Aufgaben wie das erklärte OP übermäßig komplex machen kann. Der Vorteil von Python ist jedoch, dass Sie nur das angeben, was Sie benötigen. Während der Download 20 MB groß sein kann, können Sie nur 2 MB Bibliotheken einschließen (was immer noch viel ist). Meine größte Beschwerde bei Twisted ist, obwohl sie Beispiele enthalten, alles, was über einen einfachen TCP-Server hinausgeht, den Sie selbst sind.

Obwohl es sich nicht um eine Python-Lösung handelt, habe node.js in letzter Zeit viel mehr Zugkraft erlangt. Tatsächlich habe ich darüber nachgedacht, nach kleineren Projekten zu suchen, aber ich erschrecke nur, wenn ich Javascript höre :)

Vrillusionen
quelle
Ich bin ein großer Python-Fan. - Schauen Sie sich "Javascript - The good parts" von Douglas Crockford an (3, 4 Videos). Und werfen Sie einen Blick auf CoffeeScript. Es stellt sich heraus, dass JS Dinge hat, die Python haben sollte, außer der Syntax, haha. CS hat versucht, das zu mildern, ist aber etwas ungeschickt ...
Robert Siemer
4

Es gibt ein gutes Buch zu diesem Thema: "Twisted Network Programming Essentials" von Abe Fettig. Die Beispiele zeigen, wie man sehr pythonischen Code schreibt, und für mich persönlich scheint mir das nicht auf einem aufgeblähten Framework zu beruhen. Schauen Sie sich die Lösungen im Buch an. Wenn sie nicht sauber sind, weiß ich nicht, was sauber bedeutet.

Mein einziges Rätsel ist das gleiche, das ich mit anderen Frameworks wie Ruby habe. Ich mache mir Sorgen, vergrößert es sich? Ich würde es hassen, einen Client für ein Framework zu verpflichten, das Skalierbarkeitsprobleme haben wird.

Frau Smoothie
quelle
4

Whizzer ist ein winziges asynchrones Socket-Framework, das Pyev verwendet. Es ist sehr schnell, vor allem wegen Pyev. Es wird versucht, eine ähnliche Schnittstelle bereitzustellen, die mit einigen geringfügigen Änderungen verdreht ist.

bfrog
quelle
2

Versuchen Sie auch Syncless . Es basiert auf Coroutine (ähnelt also Concurrence, Eventlet und Gevent). Es implementiert nicht blockierende Drop-In-Ersetzungen für socket.socket, socket.gethostbyname (usw.), ssl.SSLSocket, time.sleep und select.select. Es ist schnell. Es braucht Stackless Python und Libevent. Es enthält eine obligatorische Python-Erweiterung, die in C (Pyrex / Cython) geschrieben ist.

pts
quelle
2

Ich bestätige die Güte der Synchronität . Es kann libev (die neuere, sauberere und leistungsfähigere Version von libevent) verwenden. Vor einiger Zeit hat es nicht so viel Unterstützung wie libevent, aber jetzt geht der Entwicklungsprozess weiter und ist sehr nützlich.

Robert Zaremba
quelle
1

Wenn Sie nur eine vereinfachte, leichte HTTP-Anforderungsbibliothek möchten, finde ich Unirest wirklich gut

Auswurf
quelle
0

Sie können sich gerne PyWorks ansehen, das einen ganz anderen Ansatz verfolgt. Es lässt Objektinstanzen in ihrem eigenen Thread ausgeführt werden und führt Funktionsaufrufe für dieses Objekt asynchron aus.

Lassen Sie einfach eine Klasse von Task anstelle von Objekt erben und es ist asynchron. Alle Methodenaufrufe sind Proxies. Rückgabewerte (falls erforderlich) sind zukünftige Proxys.

res = obj.method( args )
# code continues here without waiting for method to finish
do_something_else( )
print "Result = %d" % res # Code will block here, if res not calculated yet

PyWorks finden Sie unter http://bitbucket.org/raindog/pyworks

renejsum
quelle
1
Dies ist zwar interessant und möglicherweise für einige Aufgaben geeignet, die Verwendung von Threads für das Netzwerk ist jedoch schlecht (insbesondere bei Python aufgrund der GIL). Und genau das war die Frage: ein Evented Framework oder mit Multiprocessing. Ihre Antwort liegt also eindeutig außerhalb des Rahmens ...
schlamar