Multiprocessing nutzlos mit urllib2?

9

Ich habe kürzlich versucht, ein kleines Tool zu beschleunigen (das urllib2 verwendet, um eine Anfrage an die (inoffizielle) twitter-button-count-URL zu senden (& gt; 2000 URLs) und das Ergebnis analysiert) mit dem Multiprocessing-Modul ( und es ist Arbeiterpools). Ich habe hier einige Diskussionen über Multithreading gelesen (was das Ganze im Vergleich zu einer Standardversion ohne Threading verlangsamte) und Multiprocessing, aber ich konnte keine Antwort auf eine (wahrscheinlich sehr einfache) Frage finden:

Können Sie URL-Aufrufe mit Multiprocessing beschleunigen oder ist der Engpass so etwas wie der Netzwerkadapter? Ich sehe nicht, welcher Teil von zB der urllib2-open-Methode parallelisiert werden könnte und wie das funktionieren soll ...

EDIT: Dies ist die Anfrage, die ich beschleunigen möchte und das aktuelle Multiprocessing-Setup:

%Vor%     
dorvak 01.08.2011, 23:48
quelle

5 Antworten

5

Werfen Sie einen Blick auf gevent und speziell auf dieses Beispiel: concurrent_download.py . Es wird schneller als Multiprocessing und Multithreading + es kann Tausende von Verbindungen problemlos bewältigen.

    
Denis Bilenko 02.08.2011, 18:19
quelle
7

Ah, hier kommt noch eine Diskussion über die GIL. Nun, hier ist das Ding. Das Abrufen von Inhalt mit urllib2 wird meist IO-gebunden sein. Natives Threading UND Multiprocessing haben beide die gleiche Leistung, wenn der Task IO-gebunden ist (Threading wird nur dann zum Problem, wenn es an die CPU gebunden ist). Ja, Sie können es beschleunigen, ich habe es selbst mit Python-Threads und so etwas wie 10 Downloader-Threads gemacht.

Im Grunde genommen verwenden Sie ein Producer-Consumer-Modell mit einem Thread (oder Prozess), der URLs zum Herunterladen produziert, und N Threads (oder Prozessen), die aus dieser Warteschlange konsumieren und Anfragen an den Server richten.

Hier ist ein Pseudocode:

%Vor%

Wenn Sie jetzt sehr große große Datenblöcke (Hunderte von MB) herunterladen und eine einzige Anforderung die Bandbreite vollständig ausfüllt, ist es sinnlos, mehrere Downloads auszuführen. Der Grund dafür, dass Sie mehrere Downloads ausführen (im Allgemeinen), ist, dass die Anforderungen klein sind und eine relativ hohe Latenz / einen hohen Overhead haben.

    
Chris Eberle 01.08.2011 23:52
quelle
3

Kommt darauf an! Kontaktieren Sie verschiedene Server, sind die übertragenen Dateien klein oder groß, verlieren Sie einen Großteil der Zeit, die darauf wartet, dass der Server antwortet, oder indem Sie Daten übertragen, ...

Im Allgemeinen erfordert Multiprocessing einen gewissen Mehraufwand, und Sie möchten daher sicher sein, dass die durch die Parallelisierung der Arbeit erzielte Beschleunigung größer ist als der Aufwand selbst.

Ein weiterer Punkt: Netzwerk- und damit I / O-gebundene Anwendungen funktionieren besser - und skalieren - mit asynchroner I / O und einer ereignisgesteuerten Architektur statt Threading oder Multiprocessing, da in solchen Anwendungen die meiste Zeit auf I / O gewartet wird. O und keine Berechnungen zu machen.

Für Ihr spezifisches Problem würde ich versuchen, eine Lösung zu implementieren, indem Sie Twisted , gevent , Tornado oder einem anderen Netzwerk-Framework, das keine Threads zum Parallelisieren von Verbindungen verwendet.

    
GaretJax 01.08.2011 23:52
quelle
1

Was Sie tun, wenn Sie Webanforderungen über mehrere Prozesse aufteilen, ist die Parallelisierung der Netzwerklatenzen (d. h. das Warten auf Antworten). Sie sollten also normalerweise eine gute Beschleunigung erhalten, da die meisten Prozesse die meiste Zeit schlafen sollten und auf ein Ereignis warten.

Oder verwende Twisted. ;)

    
pyroscope 01.08.2011 23:52
quelle
0

Nichts ist nützlich, wenn Ihr Code kaputt ist: f() (mit Klammern) ruft sofort eine Funktion in Python auf, Sie sollten stattdessen nur f (keine Klammern) übergeben, um im Pool ausgeführt zu werden. Dein Code von der Frage:

%Vor%

Beachten Sie die Klammern nach getTweets , was bedeutet, dass der gesamte Code im Hauptthread seriell ausgeführt wird.

Delegieren Sie stattdessen den Anruf an den Pool:

%Vor%

Außerdem brauchen Sie hier keine separaten Prozesse, es sei denn json.loads() ist in Ihrem Fall teuer (CPU-weise). Sie könnten Threads verwenden: ersetzen Sie multiprocessing.Pool durch multiprocessing.pool.ThreadPool - der Rest ist identisch. GIL wird während IO in CPython veröffentlicht und daher sollten Threads Ihren Code beschleunigen, wenn die meiste Zeit in urlopen().read() verbracht wird.

Hier ist ein vollständiges Codebeispiel .

    
jfs 11.12.2015 18:53
quelle