Perl线程读取输入线

时间:2017-10-02 22:23:53

标签: perl

我对线程很困惑!我希望这里有人可以提供帮助。

以下是我的代码:

$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

2 个答案:

答案 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 strictuse 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'线程中这样做。