2012-06-23 6 views
5

Estoy haciendo un montón de solicitudes HTTP y elegí HTTP :: Async para hacer el trabajo. Tengo más de 1000 solicitudes, y si simplemente hago lo siguiente (consulte el código a continuación), muchas solicitudes aguardan el tiempo de espera antes de que se procesen, ya que pueden pasar decenas de minutos antes de que el procesamiento llegue a ellas:¿Cómo realizo 25 solicitudes a la vez con HTTP :: Async en Perl?

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

Así que decidí hacer 25 solicitudes por vez, pero no puedo pensar en una forma de expresarlo en el código.

He intentado lo siguiente:

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 
    } 
} 

Sin embargo, esto no funciona así como porque es demasiado lento ahora. Ahora espera hasta que las 25 solicitudes hayan sido procesadas hasta que agregue otra 25. Entonces, si le quedan 2 solicitudes, no hace nada. Tengo que esperar a que se procesen todas las solicitudes para agregar el siguiente lote de 25.

Cómo podría mejorar esta lógica para hacer que $async haga algo mientras proceso los registros, pero también me aseguro de que no se excedan.

Respuesta

1

¡Estás cerca, solo tienes que combinar los dos enfoques! :-)

No probado, así que piénselo como pseudo código. En particular, no estoy seguro si total_count es el método correcto para usar, la documentación no lo dice. También puede tener un contador $active_requests que ++ cuando agrega una solicitud y -- cuando recibe una respuesta.

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

Si no puede llamar al wait_for_next_response lo suficientemente rápido porque está en el medio de ejecutar otro código, la solución más simple es hacer que el código sea interrumpible moviéndolo a un hilo de ejecución separado. Pero si vas a empezar a usar hilos, ¿por qué usar 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; 
+0

Hola Ikegami, trato de que ejecutar código de ejemplo pero desafortunadamente recibir el mensaje siguiente: 400 No se puede localizar método de objeto "esquema" a través de paquete "URI :: http - esto es cuestión Sheme URI pero yo uso el right URI "http://www.web.de". Puede encontrar mi código fuente en http://www.sourcepod.com/pqyyxw07-51950. thx – ovntatar

+0

lo siento, stackoverflow formateando mi enlace. El enlace es: http: // www .web. de -> borrar espacio char – ovntatar

+0

pero puedo usar cualquier otra URL y recibo el mismo error. Por ejemplo, http: // google. com – ovntatar

Cuestiones relacionadas