2012-09-09 2 views
3

제 스크립트가 멀티 스레드되도록 도와주세요. 나는 threads::shared 모듈에 대한 문서를 읽고 있지만 그것은Perl에서 멀티 스레딩

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

내가 공유 할 필요가 어떤 변수 이해할 수 없다하는 방법을 이해하는 데 도움이되지 않았다. 감사합니다 당신이 스레드를 가지고 있지 않은 경우 나에게

+0

난 당신 [당신의 마지막 질문] (HTTP에게 준 해결책 : /을 /stackoverflow.com/questions/12168495/thread-shared-perl)도 여기에 적용됩니다. – ikegami

답변

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

이/$i@a이 시간 사이에 변경되지 않습니다 있는지 확인하는 것입니다 당신이 그것을 확인하고 당신이 그것을 사용하는 시간. 이것은 잠금을 추가하여 수행됩니다.

옵션 1 :

my @a :shared = 1..79265; 
while (1) { 
    my $i; 
    { lock @a; return if [email protected]; $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 (이 그대로 사용될 수 있지만) 다음 스레드 :: 큐 용액의 기초이다. 옵션 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; 
+0

@ user1614240, 버그 수정. – ikegami

+0

@ user1614240 추가 설명 – ikegami

+0

고맙습니다. m 코드를 다시 작성했지만 작동하지 않습니다. – user1614240