0

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

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 个 url,我正在尝试创建脚本以仅处理 200 个并行请求!但不幸的是,脚本最后得到一个信息,超过 20 个线程未完成。任何想法应该是什么解决方案?

4

2 回答 2

6

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

于 2013-10-31T14:29:11.677 回答
2

您之前在评论中提出了这个问题,以询问有关按照请求发出的顺序收集响应的问题,并且您发布的代码是从该问题的答案中复制的。因此,我认为这也是您想要的。


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

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

   ...
}

通过使用工作者模型,您可以重用线程以避免启动它们所花费的时间。这也会按照您想要的顺序收集响应。

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;
于 2013-10-31T17:12:13.673 回答