Ich versuche, ungefähr 7 Dutzende von URLs parallel zu Skripten zu erhalten: der erste ist unten, mit HTTP :: Async, und der zweite ist auf Pastebin mit Net :: Async :: HTTP.
Das Problem ist, dass ich ziemlich gleiche Timing-Ergebnisse bekomme - ungefähr 8,14 Sekunden für alle URLs. Es ist inakzeptabel langsam im Vergleich zu Curl + Xargs begann von Shell, die alle in weniger als 3 Sekunden mit 10-20 "Threads" bekommt.
Zum Beispiel zeigt Devel :: Timer im ersten Skript, dass die maximale Warteschlangenlänge sogar kleiner als 6 ist ( $queue->in_progress_count
& lt; = 5, $queue->to_send_count
= 0 immer). Also, es sieht aus wie foreach mit $ queue- & gt; add ist zu langsam ausgeführt, und ich weiß nicht warum.
Ziemlich gleiche Situation habe ich mit Net :: Async :: HTTP (zweites Skript auf Pastebin), die sogar langsamer als die erste ist.
Also, bitte, weiß jemand, was ich falsch mache? Wie kann ich eine gleichlaufende Download-Geschwindigkeit erhalten, verglichen mit curl + xargs, die von Shell gestartet wurden?
%Vor%Meine besten Ergebnisse mit HTTP :: Async sind weit über 4 und bis zu mehr als 5 Sekunden. Wie ich verstehe, ist dieser Ansatz nicht erforderlich, und hier ist ein einfaches Forking-Beispiel, das ein wenig über 2 und höchstens unter 3 Sekunden dauert.
Es verwendet Parallel :: ForkManager und LWP::UserAgent für Downloads.
%Vor% Die Dateien werden mit Path :: Tiny geschrieben. Sein path
erstellt ein Objekt und spew
Routinen schreiben die Datei.
Als Referenz benötigen die sequentiellen Downloads ungefähr 26 Sekunden.
Wenn die maximale Anzahl an Prozessen auf 30 eingestellt ist, dauert dies mehr als 4 Sekunden, und mit 60 ist es etwas über 2 Sekunden, ungefähr so wie mit (bis zu) 90. In diesem Test gibt es 70 URLs.
Getestet an einem 4-Core-Laptop mit einer ordentlichen Netzwerkverbindung. (Hier ist die CPU nicht so wichtig.) Die Tests wurden wiederholt ausgeführt, mehrmals und an mehreren Tagen.
Ein Vergleich mit dem Ansatz aus der Frage
Die besten HTTP::Async
Ergebnisse sind um den Faktor zwei langsamer als die obigen. Sie sind mit 30-40 "Slots" da für höhere Zahlen die Zeit steigt, was Rätsel (mich). Das Modul verwendet select
zum Multiplexen über Net :: HTTP: : NB (eine nicht blockierende Version von Net :: HTTP ). Während select
"nicht gut skaliert", betrachtet dies Hunderte von Sockets und ich würde erwarten, mehr als 40 für dieses Netzwerk-gebundene Problem verwenden zu können. Der einfache gegabelte Ansatz tut dies.
Außerdem wird select
als eine langsame Methode zur Überwachung von Sockets betrachtet, während die Forks dies nicht einmal benötigen, da jeder Prozess seine eigene URL hat. (Dies kann den Overhead des Moduls mit vielen Verbindungen zur Folge haben.) Der inhärente Overhead von Fork ist durch den Netzwerkzugriff begrenzt und in den Schatten gestellt. Wenn wir nach (vielen) Hunderten von Downloads sind, kann das System durch Prozesse belastet werden, aber select
würde auch nicht gut laufen.
Schließlich laden select
basierte Methoden strikt eine Datei nach der anderen herunter,
und der Effekt wird durch Drucken angezeigt, da die Anfragen add
ed sind - wir können die Verzögerung sehen . Die gegabelten Downloads gehen parallel (in diesem Fall alle 70 gleichzeitig ohne Probleme). Dann wird es einen Netzwerk- oder Disketten-Engpass geben, aber das ist winzig im Vergleich zum Gewinn.
Update : Ich schob dies, um die Anzahl der Sites und Prozesse zu verdoppeln, sah keine Anzeichen von OS / CPU-Belastung und behielt die durchschnittliche Geschwindigkeit bei.
Also würde ich sagen, wenn Sie jede zweite Rasur abrasieren müssen. Aber wenn das nicht kritisch ist und es andere Vorteile von HTTP::Async
(oder so) gibt, dann sei zufrieden mit (nur ein bisschen) längeren Downloads.
Der HTTP::Async
Code, der gute Ergebnisse liefert, war einfach
Ich habe auch versucht, Header und Timings zu optimieren. (Dies beinhaltete das Ablegen von keep-alive
wie vorgeschlagen, von $request->header(Connection => 'close')
, ohne Wirkung.)
Um meinen Kommentar zu erklären. Ich war neugierig, weil ich das Net::Async::HTTP
noch nie benutzt habe, wollte dein Skript lokal ausprobieren. Also, erstellt diese minimalistische Plack app.psgi
:
Der Server versteht URLs in der Form GET /sleep_time/reqID
, wo
usleep
- und der Server schläft die angegebene Zeit bevor reagiert. Z.B. es täuscht etwas "Bearbeitungszeit" vor. z. Wenn GET /1000000/1
angefordert wird, wird der Server 1 Sekunde vor dem Antworten schlafen. Als Antwort ist die PID
des antwortenden Prozesses enthalten.
Führen Sie in einem Terminalfenster den obigen Befehl mit Starman
preforkimg server mit dem Standard 20
workers aus.
Und in dem anderen Fenster die Ergebnisse mit xargs
:
also, 20 Anfragen senden, wobei jede Antwort 1s
Bearbeitungszeit ist.
Also, 20 Anfragen = 4 Sekunden. Es ist sichtbar, dass die entsprechenden PID
unterschiedlich sind - z. B. wird die Antwort von einem anderen Arbeiter gesendet.
Verwenden Sie nun Ihr Skript async.pl
(leicht verkürzt / geändert):
Befehl
%Vor%Ergebnis
%Vor% Gleich 20 Anfragen = 20 Sekunden, und jede Anfrage wird von demselben PID
bedient. Wie die reine sequenzielle Verarbeitung. : (
Dies wahrscheinlich , weil die Anforderungen die Verbindung wiederverwenden (z. B. Keep-Alive).
Endlich - leider, wie ich sagte - habe ich keine Erfahrung mit dem Modul, also habe keine Ahnung, wie man das Modul dazu zwingt, die geöffnete Verbindung nicht wiederzuverwenden.
So, endlich funktioniert Probe ( vollständiges Skript ). Es verwendet Furl
und fork_call
von AnyEvent::Util
. Dieses Beispiel kehrt in ~ 3 Sekunden zurück, was gut genug ist. Wenn Sie eine einfache HTTP-Authentifizierung benötigen, verwenden Sie einfach URI mit folgenden Werten: username:[email protected]/path?param1=val1¶m2=val2
. Sie fügen besser use EV;
hinzu, bevor Sie AnyEvent
verwenden, weil EV am schnellsten ist.
Async ist langsamer als das parallele Herunterladen: Der asynchrone Code wird nur während einer Antwort auf andere Anrufe übertragen, aber das Herunterladen geschieht sequenziell in einem einzigen Vorgang, während die curl + xargs 100% (gut, fast 100%) funktionieren. und solange Sie die Kerne nicht sättigen) parallel, wie bei der Verwendung von Gabelarbeitern.
Bitte googeln Sie nach "Nebenläufigkeit ist keine Parallelität"
Tags und Links perl http asynchronous concurrency download