1

私は単純なクローラーを構築しようとしていますが、キューが空であっても、すべてのスレッドが終了しないようです:

#!/usr/bin/perl

use strict;
use warnings;
use threads;
use Thread::Queue;
use LWP::UserAgent;
use HTML::LinkExtor;

my $ua = new LWP::UserAgent;
my %visited = ();
my $workQueue = new Thread::Queue;

sub work {
    my ($ua, $queue, $hashref) = @_;
    my $tid = threads->self->tid;
    my $linkExtor = new HTML::LinkExtor;

    while (my $next = $queue->dequeue)
    {
        print "Processin ($tid): ", $next, "\n";

        my $resp = $ua->get ($next);
        if ($resp->is_success)
        {
            $linkExtor->parse ($resp->content);
            my @links = map { my($tag, %attrs) = @$_; 
            ($tag eq 'a')
            ? $attrs{href} : () } $linkExtor->links;

            $queue->enqueue (@links);
        }
    }
};

$workQueue->enqueue ('http://localhost');
my @threads = map { threads->create (\&work, $ua, $workQueue, \%visited) } 1..10;
$_->join for @threads;

では、これらのスレッドが終了するのを待つ正しい方法は何でしょうか? そのwhileループから飛び出すことはありません。

4

2 に答える 2

4

あなた$queue->dequeueは何かへの別のスレッドをブロックして待ってenqueueいます。perldocから:

要求された数の項目 (デフォルトは 1) をキューの先頭から削除し、それらを返します。キューに含まれる項目の数が要求された数よりも少ない場合、必要な数の項目が使用可能になるまで (つまり、他のスレッドがさらに項目を <enqueue> するまで) 、スレッドはブロックされます。

dequeue_nb()キューが空の場合は undef を返します。ただし、この場合、1 つのスレッドが最初の URL をデキューすると、アイテムがキューに入れられる前に残りのスレッドが停止します。

私の頭の上から、別のアプローチは、現在何らかのアクティビティに従事しているスレッドの数を保持し、それが0になったときに終了することでしょうか?

于 2012-11-10T15:34:32.283 に答える
1

Thread::Queue 3.01でこの問題の解決策が導入されました。これ以上アイテムがキューに追加されないことを示すキューが終了したことを宣言できるようになりました。dequeueこれにより、待機中のユーザーのブロックが解除されdequeue、キューが空のときにブロックされず、スレッドが終了できるようになります。

$workQueue->enqueue('http://localhost');
my @threads = map { threads->create (\&work, $ua, $workQueue, \%visited) } 1..10;
$workQueue->end;
$_->join for @threads;

残念なことに、キューを終了すると、アイテムをキューに追加できなくなります。そのため、Web ページをスパイダーしている最中のスレッドは、見つけたページをキューに追加できません。この制限のない元の Thread::Queue パッチを書きました。終了したキューがそれ以上のアイテムを取得できない技術的な理由はありません。この制限は Thread::Queue の作成者による設計上の選択です。彼にフィードバックを提供して、それが邪魔になっていることを知らせたいと思うかもしれません。

これは、代わりに定義し、アイテムをキューに追加し続けることを可能にする私の元のパッチです。doneenddone

于 2012-11-10T17:16:37.250 に答える