2013-10-31 29 views
0

是否有任何選項可以限制並行運行線程?在例子中,我下面的代碼: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; 
    ... 
} 

我試圖創建腳本來僅進行200並行請求,如果@URL_LIST包括超過10000個網址了!但不幸的是腳本在最後得到了一個信息,那就是20多個線程還未完成。任何想法的解決方案應該是什麼?

+0

也許你可以使用https://metacpan.org/release/ParallelUserAgent? –

回答

6

而不是產生一個線程來處理每個單獨的URL,也許你應該產生一個固定數量的工作線程,從Thread :: Queue對象中提取URL並將結果轉儲到另一個這樣的隊列中。當URL隊列清空時,工作線程可以自行結束,並且您將處理結果隊列...

+0

感謝您的建議tjd。 – ovntatar

+0

請注意,OP之前提到,應按收到的相應請求的順序收集回覆。 – ikegami

2

您之前在評論中詢問過此問題是關於按照與請求被放置,並且您發佈的代碼被從answer複製到該問題。因此,我認爲這也是你想要的。


接下來是不是最有效的解決方案,因爲沒有線程重用,但它可以很容易地收集你想要的順序的響應。

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

my @urls = ...; 

my $ua = LWP::UserAgent->new(); 
my @threads; 
for (1..200) { 
    last if [email protected]; 
    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; 
+0

使用工人模型添加了高效的解決方案。 – ikegami

+0

非常感謝,我會測試並讓你知道結果! – ovntatar