Ich öffne eine Datei mit 100.000 URLs. Ich muss eine HTTP-Anfrage an jede URL senden und den Statuscode drucken. Ich verwende Python 2.6 und habe mir bisher die vielen verwirrenden Möglichkeiten angesehen, wie Python Threading / Parallelität implementiert. Ich habe mir sogar die Python- Concurrence- Bibliothek angesehen, kann aber nicht herausfinden, wie man dieses Programm richtig schreibt. Ist jemand auf ein ähnliches Problem gestoßen? Ich denke, im Allgemeinen muss ich wissen, wie man Tausende von Aufgaben in Python so schnell wie möglich ausführt - ich nehme an, das bedeutet "gleichzeitig".
python
http
concurrency
IgorGanapolsky
quelle
quelle
requests.get
undrequests.head
(dh eine Seitenanfrage gegen eine Kopfanfrage ), verschiedene Statuscodes zurückzugeben, daher ist dies nicht der beste RatAntworten:
Verdrehte Lösung:
Dieser ist etwas schneller als die verdrehte Lösung und verbraucht weniger CPU.
quelle
concurrent*2
?conn.close()
. Wenn Sie zu viele http-Verbindungen öffnen, wird Ihr Skript möglicherweise irgendwann angehalten und Speicherplatz beansprucht.Queue
Modul wurdequeue
in Python 3 umbenannt . Dies ist Python 2-Code.Eine Lösung mit asynchroner Tornado- Netzwerkbibliothek
quelle
Die Dinge haben sich seit 2010, als dies veröffentlicht wurde, ziemlich verändert und ich habe nicht alle anderen Antworten ausprobiert, aber ich habe einige ausprobiert, und ich fand, dass dies mit Python3.6 am besten für mich funktioniert.
Ich konnte ungefähr 150 eindeutige Domänen pro Sekunde abrufen, die unter AWS ausgeführt wurden.
quelle
time1 = time.time()
oben in der for-Schleife undtime2 = time.time()
direkt nach der for-Schleife zu platzieren.Themen sind hier absolut nicht die Antwort. Sie bieten sowohl Prozess- als auch Kernel-Engpässe sowie Durchsatzbeschränkungen, die nicht akzeptabel sind, wenn das Gesamtziel "der schnellste Weg" ist.
Ein bisschen
twisted
und sein asynchronerHTTP
Client würden Ihnen viel bessere Ergebnisse liefern.quelle
Ich weiß, dass dies eine alte Frage ist, aber in Python 3.7 können Sie dies mit
asyncio
und tunaiohttp
.Sie können mehr darüber lesen und hier ein Beispiel sehen .
quelle
urls= [fetch(construct_fetch_url(u),idx) for idx, u in enumerate(some_URI_list)]
results = await asyncio.gather(*urls)
Verwenden Sie Grequests , es ist eine Kombination aus Anforderungen + Gevent-Modul.
Mit GRequests können Sie Requests with Gevent verwenden, um auf einfache Weise asynchrone HTTP-Requests zu erstellen.
Die Verwendung ist einfach:
Erstellen Sie eine Reihe nicht gesendeter Anfragen:
Senden Sie sie alle gleichzeitig:
quelle
Ein guter Ansatz zur Lösung dieses Problems besteht darin, zuerst den Code zu schreiben, der erforderlich ist, um ein Ergebnis zu erhalten, und dann Threading-Code zu integrieren, um die Anwendung zu parallelisieren.
In einer perfekten Welt würde dies einfach bedeuten, gleichzeitig 100.000 Threads zu starten, die ihre Ergebnisse zur späteren Verarbeitung in ein Wörterbuch oder eine Liste ausgeben. In der Praxis ist die Anzahl der parallelen HTTP-Anforderungen, die Sie auf diese Weise ausgeben können, jedoch begrenzt. Lokal haben Sie Grenzen, wie viele Sockets Sie gleichzeitig öffnen können und wie viele Ausführungsthreads Ihr Python-Interpreter zulässt. Aus der Ferne kann die Anzahl der gleichzeitigen Verbindungen begrenzt sein, wenn alle Anforderungen an einen oder mehrere Server gerichtet sind. Diese Einschränkungen erfordern wahrscheinlich, dass Sie das Skript so schreiben, dass jeweils nur ein kleiner Teil der URLs abgefragt wird (100, wie in einem anderen Poster erwähnt, sind wahrscheinlich eine anständige Größe des Thread-Pools, obwohl Sie dies möglicherweise feststellen kann erfolgreich viele weitere bereitstellen).
Sie können diesem Entwurfsmuster folgen, um das obige Problem zu beheben:
list
oderdict
in CPython ist, können Sie eindeutige Elemente ohne Sperren sicher an Ihre Threads anhängen oder einfügen. Wenn Sie jedoch in eine Datei schreiben oder eine komplexere threadübergreifende Dateninteraktion benötigen , sollten Sie a verwenden gegenseitige Ausschlusssperre zum Schutz dieses Staates vor Korruption .Ich würde vorschlagen, dass Sie das Threading verwenden Modul verwenden. Sie können es verwenden, um laufende Threads zu starten und zu verfolgen. Die Threading-Unterstützung von Python ist kahl, aber die Beschreibung Ihres Problems legt nahe, dass sie für Ihre Anforderungen völlig ausreichend ist.
Wenn Sie würde schließlich wie eine ziemlich einfache Anwendung eines parallelen Netzwerk - Anwendung in Python geschrieben sehen, die ssh.py . Es ist eine kleine Bibliothek, die Python-Threading verwendet, um viele SSH-Verbindungen zu parallelisieren. Das Design ist nah genug an Ihren Anforderungen, sodass Sie es möglicherweise als gute Ressource ansehen.
quelle
Wenn Sie die bestmögliche Leistung erzielen möchten, sollten Sie die Verwendung von asynchronen E / A anstelle von Threads in Betracht ziehen. Der mit Tausenden von Betriebssystem-Threads verbundene Overhead ist nicht trivial, und die Kontextumschaltung innerhalb des Python-Interpreters fügt noch mehr hinzu. Das Threading wird sicherlich die Arbeit erledigen, aber ich vermute, dass eine asynchrone Route eine bessere Gesamtleistung bietet.
Insbesondere würde ich den asynchronen Webclient in der Twisted-Bibliothek ( http://www.twistedmatrix.com ) vorschlagen . Es hat eine zugegebenermaßen steile Lernkurve, ist aber recht einfach zu bedienen, wenn Sie Twisted's asynchronen Programmierstil gut im Griff haben.
Eine Anleitung zur asynchronen Webclient-API von Twisted finden Sie unter:
http://twistedmatrix.com/documents/current/web/howto/client.html
quelle
Eine Lösung:
Testzeit:
Pingtime:
quelle
Die Verwendung eines Thread-Pools ist eine gute Option und macht dies ziemlich einfach. Leider verfügt Python nicht über eine Standardbibliothek, die Thread-Pools extrem einfach macht. Aber hier ist eine anständige Bibliothek, die Ihnen den Einstieg erleichtern soll: http://www.chrisarndt.de/projects/threadpool/
Codebeispiel von ihrer Site:
Hoffe das hilft.
quelle
q_size
> 0 die Größe der Arbeitsanforderungswarteschlange ist begrenzt , und die Thread - Pool - Blöcke , wenn die Warteschlange voll ist und es versucht , in sie (siehe mehr Arbeitsanforderungen zu stellenputRequest
Methode), es sei denn , Sie auch einen positiven verwendentimeout
WertputRequest
.“Erstellen
epoll
Objekt,öffnen viele Client - TCP - Sockets,
passen ihre Sendepuffer ein bisschen mehr als Request - Header zu sein,
einen Request - Header senden - es sollte sofort sein, nur in einen Puffer platzieren, registriert Buchse in dem
epoll
Objekt,tut
.poll
aufepoll
Obect,zuerst lesen 3 Bytes von jedem Socket aus
.poll
,schreiben Sie sie
sys.stdout
gefolgt von\n
(nicht leeren), schließen Sie den Client-Socket.Begrenzen Sie die Anzahl der gleichzeitig geöffneten Sockets. Behandeln Sie Fehler beim Erstellen von Sockets. Erstellen Sie einen neuen Socket nur, wenn ein anderer geschlossen ist.
Passen Sie die Betriebssystemgrenzen an.
Versuchen Sie, einige (nicht viele) Prozesse zu bearbeiten: Dies kann dazu beitragen, die CPU ein wenig effektiver zu nutzen.
quelle
In Ihrem Fall reicht das Threading wahrscheinlich aus, da Sie wahrscheinlich die meiste Zeit damit verbringen, auf eine Antwort zu warten. Es gibt hilfreiche Module wie Queue in der Standardbibliothek, die möglicherweise helfen.
Ähnliches habe ich beim parallelen Herunterladen von Dateien gemacht, und es war gut genug für mich, aber es war nicht in der Größenordnung, von der Sie sprechen.
Wenn Ihre Aufgabe stärker an die CPU gebunden war, sollten Sie sich das Multiprozessor- Modul ansehen, mit dem Sie mehr CPUs / Kerne / Threads verwenden können (mehr Prozesse, die sich nicht gegenseitig blockieren, da die Sperrung pro Prozess erfolgt).
quelle
Erwägen Sie die Verwendung von Windmill , obwohl Windmill wahrscheinlich nicht so viele Threads ausführen kann.
Sie können dies mit einem handgerollten Python-Skript auf 5 Computern tun, von denen jeder über die Ports 40000-60000 eine ausgehende Verbindung herstellt und 100.000 Portverbindungen öffnet.
Es kann auch hilfreich sein, einen Beispieltest mit einer QA-App wie OpenSTA durchzuführen, um eine Vorstellung davon zu bekommen, wie viel jeder Server verarbeiten kann.
Versuchen Sie auch, nur einfaches Perl mit der LWP :: ConnCache-Klasse zu verwenden. Auf diese Weise erhalten Sie wahrscheinlich mehr Leistung (mehr Verbindungen).
quelle
Dieser verdrehte asynchrone Webclient geht ziemlich schnell.
quelle
Ich fand, dass die Verwendung des
tornado
Pakets der schnellste und einfachste Weg ist, dies zu erreichen:quelle
Am einfachsten wäre es, die in Python integrierte Threading-Bibliothek zu verwenden.
Sie sind keine "echten" / Kernel-Threads.Sie haben Probleme (wie die Serialisierung), sind aber gut genug. Sie möchten einen Warteschlangen- und Thread-Pool. Eine Option ist hier , aber es ist trivial, eigene zu schreiben. Sie können nicht alle 100.000 Anrufe parallelisieren, aber Sie können 100 (oder so) gleichzeitig abfeuern.quelle