3

スクリプトをマルチスレッド化するのを手伝ってください。モジュールのドキュメントを読みましたが、そのthreads::shared方法を理解するのに役立ちませんでした

    use threads;
use threads::shared;
use LWP::UserAgent;
use HTTP::Cookies;

my $NUM_WORKERS = 2;

sub worker {
   my ($i) = @_;
   my ($web, $ck) = browser();
    ($username, $password) = split ':', $acc;
    my $url = 'http://www.site.ru/?tkn'. int(rand(10000));
    my $response = $web->post($url, Content =>
                    [//////]);
    while(1)
    {
        my $url = 'http://www.site.ru/dk?st.page='.$i.'&st.name=%D0%B0';
        my $response  = $web->get($url);
        @list = ($response->content =~ /card_wrp"><div class="photoWrapper"><div><a href="\/(.*?)\?/g);
        @popl = ($response->content =~/<\/div><div class="info">(.*?)<\/div>/g);

        for ($j = 0; $j <= scalar @list - 1; $j++)
        {
            $popl[$j] =~ s/&nbsp;//g;
            open F, ">>gr.txt";
            print F $list[$j].':'.$popl[$j]. "\n";
            close F;
        }
        print "[+] Page $i \n";

    }
}

my $i :shared = 1;
my $last = 79265;
my @workers;
for (1..$NUM_WORKERS) {
   push @workers, async {
      while (1) {
         my $i;
         {
            lock $I;
            return if $i == $last;
            $i = ++$I;
         }
         worker($i);
      }
   };
}

$_->join() for @workers;
sub browser 
{
 my $web = new LWP::UserAgent;
 my $ck = new HTTP::Cookies;
    $web->cookie_jar($ck);
    $web->agent('Opera/9.80 (Windows 7; U; en) Presto/2.9.168 Version/11.50');
    $web->requests_redirectable(0); 

    $web->timeout(5);
 return $web, $ck;
}
sub loadf {
    open (F, "<".$_[0]) or erroropen($_[0]); 
    chomp(my @data = <F>);
    close F;
    return @data;
}

どの変数を共有する必要があるのか​​ わかりません。私を助けてくれるすべてのメンバーに感謝します

4

1 に答える 1

8

スレッドがない場合、ワーク ループは次のようになります。

for my $i (1..79265) {
   worker($i);
}

問題は、変数が共有可能ではなく、共有 forできない内部状態を維持していることです。そのため、それらの問題のないものに書き直す必要があります。

オプション1:

my @a = 1..79265;
while (@a) {
   worker(shift(@a));
}

オプション 2:

my $i = 0;
while (++$i <= 79265) {
   worker($i);
}

いずれかのバージョンを並列化するために必要なのは、 / を確認するときと使用するときの間で@a/$iが変わらないようにすることだけです。これは、ロックを追加することによって行われます。

オプション1:

my @a :shared = 1..79265;
while (1) {
   my $i;
   { lock @a; return if !@a; $i = shift(@a); }
   worker($i);
}

オプション 2:

my $I :shared = 1;
while (1) {
   my $i;
   { lock $I; $i = $I; return if ++$I > 79265; }
   worker($i);
}

オプション 1 は、次の Thread::Queue ソリューションの基礎です (ただし、そのまま使用することもできます)。オプション 2 は、以下でそのまま使用されます。


私は通常Thread::QueueまたはThread::Queue::Anyを使用します:

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

my $NUM_WORKERS = 5;

sub worker {
   my ($i) = @_;
   ... put your download code here ...
}

my $q = Thread::Queue->new();
my @workers;
for (1..$NUM_WORKERS) {
   push @workers, async {
      while (defined(my $i = $q->dequeue())) {
         worker($i);
      }
   };
}

$q->enqueue($_) for 1..79265;
$q->enqueue(undef) for @workers;
$_->join() for @workers;

しかし、ここでは簡単に行うことができます:

use threads;
use threads::shared;

my $NUM_WORKERS = 5;

sub worker {
   my ($i) = @_;
   ... put your download code here ...
}

my $I :shared = 1;
my $last = 79265;
my @workers;
for (1..$NUM_WORKERS) {
   push @workers, async {
      while (1) {
         my $i;
         {
            lock $I;
            $i = $I;
            return if ++$I > $last;
         }
         worker($i);
      }
   };
}

$_->join() for @workers;
于 2012-09-09T20:05:51.163 に答える