如何在Perl中处理具有依赖项的调度线程?

时间:2010-08-10 10:53:25

标签: multithreading perl

我有以下情况:

sub_1 can run immediately
sub_2 can run immediately
sub_3 can run only after sub_1 finishes
sub_4 can run only after sub_1 finishes
sub_5 can run only after sub_2 finishes
sub_6 can run only after sub_2 finishes
sub_7 can run only after both sub_1 and sub_2 finish
sub_8 can run only after both sub_1 and sub_2 finish

我希望每个sub尽快开始运行,而不是等待所有sub完成。

我非常感谢您帮助为这个简单的场景创建一个干净的解决方案 - 我是多线程的新手。

我不确定它是否有所作为,但这些潜艇都在一个物体中。

3 个答案:

答案 0 :(得分:4)

我建议使用“Boss / Worker”模型,其中一个线程管理要在工作线程中执行的子程序,工作线程又在完成时将其状态报告给老板。

在这个模型中,boss是唯一需要知道如何排序任务的线程。它可能看起来像这样:

use threads;
use Thread::Queue;
use Thread::Pool;

our $done_queue = Thread::Queue->new;
our $work_pool  = Thread::Pool->new;

sub sub_1 {
  ... do the work ...
  $done_queue->enqueue('sub_1'); # tell the boss we're all done
}

sub sub_2 {
  ... do the work ...
  $done_queue->enqueue('sub_2'); # tell boss we're done
}

...

# Main loop (boss thread)

$work_pool->enqueue(\&sub_1);
$work_pool->enqueue(\&sub_2);

while (my $sub_name = $done_queue->dequeue) {
  # You, the boss thread, keep track of state and
  # transitions however you like.  You know what's
  # just finished and what's finished in the past
  ...
}

当然,抽象可以使整洁 - 你可以隐藏单个对象后面的池和队列,一个不需要sub_1()来了解状态队列的对象:

$boss->enqueue( 'sub_1' => \&sub_1 ); # Will return 'sub_1' via await_completed()
$boss->enqueue( 'sub_2' => \&sub_2 ); # Will return 'sub_1'

while (my $sub_name = $boss->await_completed) {
  ...
}

答案 1 :(得分:1)

这是使用线程和线程共享的可能解决方案。大多数代码只是模拟测试并模拟在完成之前必须“工作”的线程。在该示例中,主线程产生七个线程,每个线程具有他们必须“工作”的随机时间量。线程无法开始工作,直到它们依赖的其他线程(在依赖项数组中设置)完成。您可以更改线程依赖关系并运行几次示例以说明它可以正常工作。

此外,您可以让每个线程在运行后终止,并在所有子线程完成后通过检查状态哈希使主线程终止。

use strict;
use warnings;
use threads;
use threads::shared;


my %status : shared;

my $dependencies = [
                    {3 => 1},   #three can only run after one has finished...
                    {4 => 1},   #four can only run after one has finished...
                    {5 => 2},   #five can only run after two has finished...
                    {6 => 1},   #etc...
                    {6 => 2},
                    {7 => 1},
                    {7 => 2}
                   ];

main();

sub main{
    foreach my $thread_number (1..7){
        spawn_thread($thread_number);
    }

    while(1){
        print "I am the main thread\n";
        sleep(1);
    }
}

sub spawn_thread{
    my $thread_number = shift;
    $status{$thread_number} = 'wait';
    my $thr = threads->new(\&thread_routine, $thread_number); 

}

sub thread_routine{
    my $thread_number = shift;

    my $working_time_left =  int(rand(5)) + 1;    #make a random time that this thread needs to "work"

    while(1){
        print "I am thread number $thread_number with status $status{$thread_number}\n";
        {
            lock(%status);

                    #see if this thread is active;  if so, see if it finished running running
            if ($status{$thread_number} eq 'active'){
                if ($working_time_left <= 0){
                    $status{$thread_number} = 'ran';
                }
            }
            else{       
                            #see if we can activate                 
                if ($status{$thread_number} eq 'wait'){
                    my $can_activate = 1;
                    foreach my $index (0..$#$dependencies){
                        if (exists $dependencies->[$index]->{$thread_number}){
                            if ($status{$dependencies->[$index]->{$thread_number}} ne 'ran'){
                                $can_activate = 0;
                                last;
                            }
                        }
                    }
                    if ($can_activate){                 
                        $status{$thread_number} = "active";
                    }
                }

            }
        }

        sleep(1);

        if ($status{$thread_number} eq 'active'){   #do "work"
            $working_time_left--;
        }
    }
}

答案 2 :(得分:0)

分叉并创建2个进程:

在流程1中:

sub_1; sub_3

在过程2中:

sub_2; wait for sub_1 end; sub_4