6

我正在做很多 HTTP 请求,我选择了 HTTP::Async 来完成这项工作。我有超过 1000 个请求要发出,如果我只是执行以下操作(请参见下面的代码),很多请求在处理时就会超时,因为处理到达它们可能需要数十分钟:

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

所以我决定每次做 25 个请求,但是我想不出用代码来表达它的方法。

我尝试了以下方法:

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

然而,这并不能很好地工作,因为它现在太慢了。现在它一直等到所有 25 个请求都已处理完毕,直到它添加另外 25 个请求。因此,如果还剩下 2 个请求,它什么也不做。我必须等待处理所有请求以添加下一批 25。

在处理记录的同时,我如何改进这个逻辑$async来做一些事情,同时还要确保它们不会超时。

4

2 回答 2

2

如果wait_for_next_response由于正在执行其他代码而不能足够快地调用,最简单的解决方案是通过将代码移动到单独的执行线程来使代码可中断。但是,如果您要开始使用线程,为什么要使用 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 (1..@urls) {
   my $res = $res_q->dequeue();
   ...
}

$_->join() for @workers;
于 2012-06-23T21:33:40.763 回答
2

你很接近,你只需要结合这两种方法!:-)

未经测试,因此将其视为伪代码。特别是我不确定是否total_count是正确的使用方法,文档没有说。您也可以在添加请求和收到响应时设置一个$active_requests计数器。++--

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);

}
于 2012-06-24T04:02:20.687 回答