并行请求的线程的Perl最大限制

时间:2013-10-31 14:18:17

标签: multithreading perl

是否有任何限制并行运行线程的选项。在示例中,我有以下代码:

use threads;
use LWP::UserAgent qw( );

my $ua = LWP::UserAgent->new();
my @threads;
# if @threads < 200
for my $url (@URL_LIST) {
   push @threads, async { $ua->get($url) };
}
# if @threads <= 200
for my $thread (@threads) {
   my $response = $thread->join;
   ...
}

如果@URL_LIST包含超过10000个网址,我尝试创建脚本以仅执行200个并行请求!但不幸的是,脚本最终得到的信息是20多个线程未完成。任何想法解决方案应该是什么?

2 个答案:

答案 0 :(得分:6)

不是产生一个线程来处理每个URL,也许你应该产生一定数量的工作线程,这些线程从Thread :: Queue对象中提取URL并将结果转储到另一个这样的队列中。当URL队列清空时,工作线程可以自行结束,并且您将继续处理结果队列...

答案 1 :(得分:2)

您之前在评论中询问了此问题,询问是否按照与请求相同的顺序收集回复,并且您发布的代码已从answer复制到该问题。因此,我认为这也是你想要的。


以下不是最有效的解决方案,因为没有线程重用,但它可以很容易地按照您想要的顺序收集响应。

use threads;
use LWP::UserAgent qw( );

my @urls = ...;

my $ua = LWP::UserAgent->new();
my @threads;
for (1..200) {
   last if !@urls;
   my $url = shift(@urls);
   push @threads, async { $ua->get($url) };
}

while (@threads) {
   my $thread = shift(@threads);
   my $response = $thread->join;

   if (@urls) {
      my $url = shift(@urls);
      push @threads, async { $ua->get($url) };
   }

   ...
}

通过使用worker模型,您可以重用线程以避免启动它们所需的时间。这也按您希望的顺序收集回复。

use threads;
use Thread::Queue 3.01 qw( );

my $request_q  = Thread::Queue->new();
my $response_q = Thread::Queue->new();

my @threads;
push @threads, async {
   my $ua = LWP::UserAgent->new();
   while (my $url = $request_q->dequeue()) {
      $response_q->enqueue([ $url, $ua->get($url) ]);
   }
};

$request_q->enqueue($_) for @urls;
$request_q->end();

my %responses;
for my $url (@urls) {
   while (!$responses{$url}) {
      my ($response_url, $response) = @{ $response_q->dequeue() };
      $responses{$response_url} = $response;
   }

   my $response = delete($responses{$url});
   ...
}

$_->join for @threads;