2011-10-21 4 views
2

私は例えば、私は、このコードで20個のスレッドを使用したい...私のプログラムの速度を上げるためにPerlでスレッドを使用する場合:上記のコードでPerlでスレッドを使うには?

use IO::Socket; 
my $in_file2 = 'rang.txt'; 
open DAT,$in_file2; 
my @ip=<DAT>; 
close DAT; 
chomp(@ip); 
foreach my $ip(@ip) 
{ 
    $host = IO::Socket::INET->new(
     PeerAddr => $ip, 
     PeerPort => 80, 
     proto => 'tcp', 
     Timeout=> 1 
    ) 
    and open(OUT, ">>port.txt"); 
    print OUT $ip."\n"; 
    close(OUT); 
} 

我々はIPSとスキャンのリストを与えます所定のポート。このコードでスレッドを使用します。私のコードの速度を上げる他の方法はありますか?

ありがとうございました。

答えて

3

Perlはスレッディングとフォークの両方を行うことができます。 「スレッド」は公式には推奨されていません。それはあまり理解されておらず、多分反抗的ではありません。プログラミング言語のスレッドのように軽量ではありません。

特にスレッドに敏感な人は、スレッドごとのスレッドを生成するよりも、スレッドの「ワーカー」モデルが優れています。後者はいくつかの言語で行うことができます - perlでは非常に非効率的です。これは、照合し、印刷結果、IPリストと(20)ワーカースレッドのセットを供給し、それらを介して自分の道を動作するようにキューを使用しています

#!/usr/bin/env perl 

use strict; 
use warnings; 

use threads; 
use Thread::Queue; 
use IO::Socket; 

my $nthreads = 20; 

my $in_file2 = 'rang.txt'; 

my $work_q = Thread::Queue->new; 
my $result_q = Thread::Queue->new; 

sub ip_checker { 
    while (my $ip = $work_q->dequeue) { 
     chomp($ip); 
     $host = IO::Socket::INET->new(
      PeerAddr => $ip, 
      PeerPort => 80, 
      proto => 'tcp', 
      Timeout => 1 
     ); 
     if (defined $host) { 
      $result_q->enqueue($ip); 
     } 
    } 
} 

sub file_writer { 
    open(my $output_fh, ">>", "port.txt") or die $!; 
    while (my $ip = $result_q->dequeue) { 
     print {$output_fh} "$ip\n"; 
    } 
    close($output_fh); 
} 


for (1 .. $nthreads) { 
    push(@workers, threads->create(\&ip_checker)); 
} 
my $writer = threads->create(\&file_writer); 

open(my $dat, "<", $in_file2) or die $!; 
$work_q->enqueue(<$dat>); 
close($dat); 
$work_q->end; 

foreach my $thr (@workers) { 
    $thr->join(); 
} 

$result_q->end; 
$writer->join(); 

は、そのようにあなたはこのような何かを行う可能性がありますwriterスレッドを使用します。

しかし、スレッドが実際にこれ以上推奨されていないとして、より良い方法は行くかもしれないあなたのコードでどのParallel::ForkManagerを使用するのが良いかもしれない。このようなビット:あなたは、ファイルIOの特に注意する必要があります

#!/usr/bin/env perl 

use strict; 
use warnings; 

use Fcntl qw (:flock); 
use IO::Socket; 

my $in_file2 = 'rang.txt'; 
open(my $input, "<", $in_file2) or die $!; 
open(my $output, ">", "port.txt") or die $!; 

my $manager = Parallel::ForkManager->new(20); 
foreach my $ip (<$input>) { 
    $manager->start and next; 

    chomp($ip); 
    my $host = IO::Socket::INET->new(
     PeerAddr => $ip, 
     PeerPort => 80, 
     proto => 'tcp', 
     Timeout => 1 
    ); 
    if (defined $host) { 
     flock($output, LOCK_EX); #exclusive or write lock 
     print {$output} $ip, "\n"; 
     flock($output, LOCK_UN); #unlock 
    } 
    $manager->finish; 
} 
$manager->wait_all_children; 
close($output); 
close($input); 

マルチプロセッシングの場合、全体のポイントが実行シーケンスであるため、もはや明確に定義されていません。したがって、別のスレッドが開いているがディスクにフラッシュされていないファイルを壊してしまう別のスレッドで終わるのは非常に簡単です。

私はあなたのコードに注意します。ファイルを開いていないと、印刷しないことに頼っているようです。これは素晴らしいことではありません。特にファイルハンドルがレキシカルスコープでない場合にはそうです。

しかし、上記で概説した両方のマルチプロセッシングのパラダイム(これは他にもありますが、これが最も一般的です)では、ファイルIOのシリアル化を扱う必要があります。あなたの「結果」は、タスクが完了したときに非常に依存するため、両方でランダムな順序になることに注意してください。それがあなたにとって重要なのであれば、スレッドまたはフォークが完了した後で照合しソートする必要があります。

それはフォークの方に見て、おそらく一般的にはましだ - threadsドキュメントでは、上記の言ったように:

のPerlが提供する「インタプリタベースのスレッドが」1が期待するかもしれないマルチタスクのための高速、軽量なシステムではありませんまたは希望します。スレッドは、それらを誤用しやすい方法で実装されています。それらを正しく使用する方法を知っている人や、ヘルプを提供できる人はほとんどいません。 perlでインタプリタベースのスレッドを使用することは正式には推奨されません。

関連する問題