我想在Perl中使用线程来提高程序的速度...例如我想在这段代码中使用20个线程:
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列表并扫描给定的端口。我想在这段代码中使用线程。有没有其他方法可以提高我的代码速度?
感谢。
答案 0 :(得分:6)
您可能希望查看AnyEvent::Socket或Coro::Socket,POE或Parallel::ForkManager,而不是使用主题。
答案 1 :(得分:4)
答案 2 :(得分:3)
Perl可以同时进行线程化和分叉。 &#34;螺纹&#34;官方不推荐 - 在很大程度上是因为它没有被很好地理解,并且 - 或许有点违反规范 - 不像线程在某些编程语言中那样轻量级。
如果你特别热衷于线程,那么“工作人员”会在线程模型比每个任务产生一个线程要好得多。你可能会用某些语言来做后者 - 在perl中效率非常低。
因此你可能会这样做:
#!/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();
这使用一个队列来为一组(20)工作线程提供一个IP列表,并通过它们进行处理,通过writer
线程进行整理和打印结果。
但由于线程不再被推荐,更好的方法是使用Parallel::ForkManager
,你的代码可能有点像这样:
#!/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,因为整点都不再是你的执行顺序。因此,在另一个线程已经打开但没有刷新到磁盘的情况下,最终会有不同的线程破坏文件。
我注意到你的代码 - 你似乎依赖于打开文件失败,以便不打印它。这不是一件好事,特别是当您的文件句柄没有词法范围时。
但是在我上面概述的两种多处理范例中(还有其他一些,这些是最常见的)你还需要处理文件IO序列化。请注意您的结果&#39;两者都是随机顺序,因为它非常依赖于任务完成的时间。如果这对您很重要,那么您需要在完成线程或分叉后进行整理和排序。
如上所述,在threads
文档中,通常可能更好地展望分叉:
&#34;基于解释器的线程&#34;由Perl提供的并不是人们可能期望或希望的快速,轻量级的多任务处理系统。线程的实现方式使其易于滥用。很少有人知道如何正确使用它们或能够提供帮助。 官方不鼓励在perl中使用基于解释器的线程。