我对线程很困惑!我希望这里有人可以提供帮助。
以下是我的代码:
$LOGFILE = "log.txt";
open(LOGFILE) or die("Could not open log file.");
foreach $line (<LOGFILE>) {
chomp($line);
my $number = shift;
system("echo $number total lines > count");
print "This thread is printing the number $number\n";
sleep(1);
log.txt
:
答案 0 :(得分:1)
use strict;
use warnings qw( all );
use threads;
use Thread::Queue qw( ); # 3.01+
use constant NUM_WORKERS => 10;
sub worker {
my ($job) = @_;
print("This is log $job\n");
}
{
my $log_qfn = "log.txt";
open(my $log_fh, '<', $log_qfn)
or die("Can't open \"$log_qfn\": $!\n");
my $q = Thread::Queue->new();
for (1..NUM_WORKERS) {
async {
while (defined( my $job = $q->dequeue() )) {
worker($job);
}
};
}
while (my $line = <$log_fh>) {
chomp($line);
$q->enqueue($line);
}
$q->end();
$_->join() for threads->list();
}
当然,输出不一定是相同的顺序。如果你需要它,它将需要做很多额外的工作。
答案 1 :(得分:0)
首先 - 在我们进入线程之前,你的代码存在很多问题。因为并行代码引入了一个全新的错误,所以开始使用合适的代码真是非常重要。
你甚至没有编译,也没有单线程工作。
LOGFILE
和$LOGFILE
不是一回事。foreach
读取文件句柄 - 请使用while
。 @threads
数组 - 大部分都不需要,因为您有threads->list
。 use strict
和use warnings;
- 线程混乱并创建全新的错误类别和间歇性错误。在引入额外的复杂性之前,您的代码必须是防弹的。 这里有一个基本点 - 线程是不确定的。重点是 - 您不再具有已定义的执行顺序,因此不能依赖于任何特定的输出顺序。
另外 - 线程是官方不鼓励因为它被误解了 - perl线程不是轻量级的,所以产生大量的线程非常低效。如果你想走这条路,那么Parallel::ForkManager
可能就是这项工作的工具。
甚至将它放在一边 - 它们并行计算资源,而不是磁盘IO。如果您只是“只是”读取文件,那么您将不会让它比磁盘控制器更快,这是您的限制因素。
无论如何,做你的事:
#!/usr/bin/env perl
use strict;
use warnings;
use threads;
use Thread::Queue qw ( );
my $num_threads = 10;
my $work_q = Thread::Queue -> new;
my $output_q = Thread::Queue -> new;
sub worker {
my $count = 0;
print "Worker: ", threads -> self -> tid, " started and waiting for input\n";
while ( my $item = $work_q -> dequeue ) {
$output_q -> enqueue ( threads -> self -> tid. ": ". $count++. " items: $item");
print "Processing: $item";
}
print "Worker: ", threads -> self -> tid, " exiting\n";
}
sub serialise_output {
print "Serialiser waiting for things to print: ", threads -> self -> tid,"\n";
while ( my $output_item = $output_q -> dequeue ) {
print $output_item,"\n";
}
}
my @workers = map { threads -> create ( \&worker ) } 1..$num_threads;
my $serialiser = threads -> create ( \&serialise_output );
open ( my $input, '<', 'log.txt' ) or die $!;
while ( my $line = <$input> ) {
chomp ( $line ) ;
$work_q -> enqueue ( $line );
}
close ( $input );
$work_q -> end; #tell the threads that's all of it, so they exit.
$_ -> join for @workers; #wait for all the workers to exit.
$output_q -> end; #need to wait for workers to finish, so we don't create race condition.
$serialiser -> join;
print "All threads done\n";
注意 - 序列化程序以相当随机的顺序获取它的输入,基于哪个线程处理了哪一行。您可以直接将其流式传输到打开的文件句柄(不要尝试在多个线程中打开相同的文件 - 这会变得很难看)或者在打印之前进行某种排序和合并。
你绝对不能依赖你的文件io的任何排序,因为你正在分工 - 这是重点。但是如果你要等到所有这一切(例如,如果你要对它进行排序),你就不需要一个单独的线程来序列化输出 - 你可以在'main'线程中这样做。