是否有任何限制并行运行线程的选项。在示例中,我有以下代码:
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多个线程未完成。任何想法解决方案应该是什么?
答案 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;