PERL - 多线程 - 儿童+孙子 - 线程运行限制

时间:2014-10-04 06:41:30

标签: multithreading perl

我创建了一个Perl脚本,我在其中创建了线程(在此期间运行的线程方面受限)并且每个线程都创建了自己的子节点,这些子节点的数量也应该有限。

在我托管脚本的地方,我不能同时为每个Perl脚本启动超过X个线程。在下面的例子中,我同时X = 3 x 7 = 21个线程。

  • 3表示第一份工作($nb_process_first
  • 7表示第二份工作($nb_process_second

问题:

  1. 有没有更好的方法来管理线程和他们的孩子? (以队列为例 - 你能不能给我一些代码示例,因为我试过没有成功)
  2. 我的当前脚本没有以所有加入的线程终止,尽管我在所有正在运行的线程上使用循环来加入它们(参见脚本的末尾)。
  3. #!/usr/bin/perl -s
    
    use threads;
    
    my @threads;
    my $nb_process_first = 3;
    my @running          = ();
    
    print "START" . "\n";
    
    $current = 1;
    while ( $current <= 10 ) {
        @running = threads->list(threads::running);
        if ( scalar @running < $nb_process_first ) {
            print "Launch firstJob=" . scalar @running . "\n";
            my $thread = threads->create( \&firstJob );
            push( @threads, $thread );
        } else {
            redo;
        }
        $current++;
    }
    
    my @joinable = threads->list(threads::joinable);
    while ( scalar @joinable != 0 ) {
        foreach my $thr ( threads->list() ) {
            $thr->join();
        }
        @joinable = threads->list(threads::joinable);
    }
    
    print "END" . "\n";
    
    sub secondJob {
        for ( $i = 0; $i <= 15; $i++ ) {
            print "secondJob=" . $i . "\n";
            sleep 1;
        }
        threads->exit();
    }
    
    sub firstJob {
        my $nb_process_second = 7;
        my @running           = ();
        $current = 1;
        while ( $current <= 10 ) {
            @running = threads->list(threads::running);
            if ( scalar @running < $nb_process_second ) {
                print "firstJob/Launch secondJob=" . scalar @running . "-" . $current . "\n";
                my $secondthread = threads->create( \&secondJob );
                push( @threads, $secondthread );
                sleep 2;
            }
            $current++;
        }
        threads->exit();
    }
    

2 个答案:

答案 0 :(得分:0)

至于你的第二个问题,线程只有在完成运行后才能连接(参见this answer)。因为某些线程在第二个while循环运行时没有完成,所以它完成后不加入它们。

您的循环应该根据活动线程数而不是可连接线程数来等待。像这样:

while (threads->list() > 0)
{
   foreach my $joinable (threads->list(threads::joinable))
   {
       $joinable->join();
   }
}

至于第一个问题,肯定有其他方法可以管理线程。但是,如果不了解您的任务,就无法说出您应该做些什么。

答案 1 :(得分:0)

Thread::Queue是基本&#39;工作线程的便捷模型。线程代码模型。

有点像这样:

#!/usr/bin/perl
use strict;
use warnings;
use threads;
use Thread::Queue;

my $firstworkitem_q = Thread::Queue -> new();
my $secondworkitem_q = Thread::Queue -> new();
my $nthreads = 10; 

sub first_worker {
   while ( my $item = $firstworkitem_q -> dequeue() ) {
       print "First worker picked up $item, and queues it to second worker\n";
       $secondworkitem_q -> enqueue ( $item ); 
   }
}

sub second_worker {
   while ( my $item = $secondworkitem_q -> dequeue() ) {
       print "Second worker got $item"; 
   }
}

my @first_workers;
for ( 1..$nthreads ) {
    my $thr = threads -> create ( \&first_worker );
    push ( @first_workers, $thr );
}

for ( 1..$nthreads ) {
    my $thr = threads -> create ( \&second_worker );
}

$firstworkitem_q -> enqueue ( @things_to_processs );
$firstworkitem_q -> end;

foreach my $firstworker ( @first_workers ) {
   $firstworker -> join();
}

#here all the first workers have finished, so we know nothing will be queued to second work queue. 
$secondworkitem_q -> end();

foreach my $thr ( threads -> list() ) {
    $thr -> join();
}

你把东西塞进队列,然后迭代它进行处理。当你end队列时,while循环得到undef并因此终止 - 使你的线程可以连接。

您不需要按照您的方式跟踪@running,因为threads -> list()会这样做。更重要的是 - 你需要让@running成为共享变量并将其锁定,因为否则你在每个线程中都有不同的副本。

firstJob产生secondJob我会远离它,因为它会产生各种各样的果味错误。我建议产生两类工作线程。使用$queue -> end()触发要关闭的第一组工作人员。