Hoe maak ik 25 aanvragen tegelijk met HTTP :: Async in Perl?

Ik doe veel HTTP-verzoeken en ik koos voor HTTP :: Async om het werk te doen. Ik heb meer dan 1000 verzoeken om te maken en als ik eenvoudigweg het volgende doe (zie onderstaande code), komen er veel time-outs voor de verwerkingstijd omdat het tientallen minuten kan duren voordat de verwerking hen bereikt:

for my $url (@urls) {
    $async->add(HTTP::Request->new(GET => $url));
}
while (my $resp = $async->wait_for_next_response) {
    # use $resp
}

Dus besloot ik om 25 verzoeken per keer te doen, maar ik kan geen manier bedenken om het in code uit te drukken.

Ik probeerde het volgende:

while (1) {
    L25:
    for (1..25) {
        my $url = shift @urls;
        if (!defined($url)) {
            last L25;
        }
        $async->add(HTTP::Request->new(GET => $url));
    }
    while (my $resp = $async->wait_for_next_response) {
        # use $resp
    }
}

Dit werkt echter niet goed omdat het nu te traag is. Nu wacht het totdat alle 25 verzoeken zijn verwerkt totdat het nog een 25 toevoegt. Dus als er nog 2 verzoeken over zijn, doet het niets. Ik moet wachten tot alle aanvragen zijn verwerkt om de volgende batch van 25 toe te voegen.

Hoe kan ik deze logica verbeteren om $ async iets te laten doen terwijl ik records verwerk, maar zorg er ook voor dat ze geen time-out hebben.

6

2 antwoord

Als u wait_for_next_response niet snel genoeg kunt aanroepen omdat u bezig bent met het uitvoeren van andere code, is de eenvoudigste oplossing om de code te onderbreken door deze naar een aparte thread van uitvoering te verplaatsen. Maar als u gaat beginnen met het gebruik van threads, waarom gebruikt u HTTP :: Async?

use threads;
use Thread::Queue::Any 1.03;

use constant NUM_WORKERS => 25;

my $req_q = Thread::Queue::Any->new();
my $res_q = Thread::Queue::Any->new();

my @workers;
for (1..NUM_WORKERS) {
   push @workers, async {
      my $ua = LWP::UserAgent->new();
      while (my $req = $req_q->dequeue()) {
         $res_q->enqueue( $ua->request($req) );
      }
   };    
}

for my $url (@urls) {
   $req_q->enqueue( HTTP::Request->new( GET => $url ) );
}

$req_q->enqueue(undef) for @workers;

for ([email protected]) {
   my $res = $res_q->dequeue();
   ...
}

$_->join() for @workers;
2
toegevoegd
toegevoegd de auteur ikegami, de bron
Hallo ikegami, ik probeer je voorbeeldcode uit te voeren, maar helaas ontvang ik het volgende bericht: 400 Kan objectmethode niet vinden "schema" via pakket "URI :: http - dit is URI sheme-probleem maar ik gebruik de juiste URI" web.de & quot ;. je kunt mijn broncode vinden in sourcepod.com/pqyyxw07-51950 . Dankje
toegevoegd de auteur ovntatar, de bron
sorry, stackoverflow formatteren van mijn link. de link is: http://www. web. de -> verwijder spatie char
toegevoegd de auteur ovntatar, de bron
maar ik kan elke andere URL gebruiken en krijg dezelfde foutmelding. e-g http://google. com
toegevoegd de auteur ovntatar, de bron
Succesvol bijgewerkte URI-1.64 (opgewaardeerd van 1.60) Ik test het probleem op fedora (x86_64 GNU/Linux) perl 5.16 en ubuntu (i686 athlon i386 GNU/Linux) perl 5.14. misschien ga ik een vraag stellen voor deze bug
toegevoegd de auteur ovntatar, de bron

Je bent dichtbij, je hoeft alleen maar de twee benaderingen te combineren! :-)

Niet getest, dus denk eraan als pseudo-code. In het bijzonder weet ik niet zeker of total_count de juiste methode is om te gebruiken, zegt de documentatie niet. U kunt ook een $ active_requests -teller hebben die u ++ gebruikt bij het toevoegen van een aanvraag en - wanneer u een antwoord krijgt.

while (1) {

   # if there aren't already 25 requests "active", then add more
   while (@urls and $async->total_count < 25) {
       my $url = shift @urls;
       $async->add( ... );
   }

   # deal with any finished requests right away, we wait for a
   # second just so we don't spin in the main loop too fast.
   while (my $response = $async->wait_for_next_response(1)) {
      # use $response
   }

   # finish the main loop when there's no more work
   last unless ($async->total_count or @urls);

}
2
toegevoegd