2013-06-26 68 views
7

我一直在写一个“检查”系统,对各种服务,系统,数据库,文件等执行各种“检查”。“检查”本质上是通用的,可以是任何东西。所有检查都以通用或失败的通用格式报告,无论可能如何。“任何”代码的Perl异步任务,无论它是什么?

它以模块化OO方式编写,因此开发人员可以简单地遵循框架并独立于其他编写框架来编写检查。每个对象都包含一个共享的报告对象,在他们运行检查后,他们只需$ self - > {'reporting'} - > report(params)。参数被定义并且开发者被假定适当地报告。报告对象然后索引这些报告。我的主要装载机脚本有条目,如下列:

my $reportingObject = new Checks::Reporting(params); 
my @checks; 

push @checks, new Checks::Check_One($reportingObject, params)); 
push @checks, new Checks::Check_One($reportingObject, params)); 
. 
. 
push @checks, new Checks::Check_N($reportingObject, params)); 

揭开序幕检查并完成一次他们这样做我一直在做的报告:

foreach my $check (@checks) { 
    $check->run_stuff(); 
} 

$reportingObject->finalize_report(); 

现在,因为这些检查是完全独立的(不必担心报告对象),它们可以并行运行。作为改进我做:

my @threads; 
foreach my $check (@checks) { 
    push @threads, async { $check->run_stuff(); } 
} 

foreach my $thread (@threads) { 
    $thread->join; 
} 

#All threads are complete, and thus all checks are done 
$reportingObject->finalize_report(); 

正如我刚才所说的开发商将彼此独立的写检查。一些检查很简单,而另一些则不是。简单的检查可能没有异步代码在其中,但其他人可能需要运行异步内部如

sub do_check { 
    my @threads; 
    my @list = @{$self->{'list'}}; 

    foreach my $item (@list) { 
     push @threads, async { 
        #do_work_on_$item 
        #return 1 or 0 for success or fail 
       }; 
     foreach my $thread (@threads) { 
      my $res = $thread->join; 
      if($res == 1) { 
       $self->{'reporting'}->report(params_here); 
      } 
     } 
    } 
} 

正如你所看到的线程模型可以让我做的事情非常含糊其辞。每个“检查”,无论它在自己的线程中独立运行。如果一个开发人员有异步的东西要做,不管它是什么,他只需要在自己的线程中独立完成。我想要一个类似于这个的模型。

不幸的是线程速度慢,效率低下。所有的异步库都有特定的观察者,比如IO等。我不需要任何特定的东西。我想要一个基于事件的模型,它允许我简单地启动异步任务,无论它们是什么,只要通知完成后我就可以继续。

希望这可以解释它,你可以指向正确的方向。

+2

只是一个样式注释,避免[间接对象语法]是一个好主意(http://modernperlbooks.com/mt/2009/08/the-problems-with-indirect-object-notation.html) – friedo

+0

AFAIK “异步库”总是为工作做'具体IO'然后'呼叫FUNC它收集IO results' –

+1

什么你的意思做“线程缓慢和低效”?另外,为什么当你使用[内建线程](http://perldoc.perl.org/threads.html)来做到这一点时,你使用了一个异步库? –

回答

6

这似乎是一个不错的选择为老板工人型号:

  • 菌种几个工人在节目的开头。确保他们都有权访问队列。

  • 按照您的喜好排列尽可能多的支票。工作人员将检查出队,执行它们,并将结果排入输出队列。

  • 您的主线程查看输出线程的结果,并执行任何想要的操作。

  • 加入工人在END

你可能想看看Thread::Queue::Any如果你想要把coderefs到队列中的机会。

这里是一个完全可运行的例子:

use strict; use feature 'say'; 
use threads; use threads::shared; use Thread::Queue::Any; 
use constant NUM_THREADS => 5; 
local $Storable::Deparse = 1; local $Storable::Eval = 1; # needed to serialize code 

my $check_q = Thread::Queue::Any->new; 
my $result_q = Thread::Queue::Any->new; 

# start the workers 
{ 
    my $running :shared = NUM_THREADS; 
    my @threads = map threads->new(\&worker, $check_q, $result_q, \$running), 1..NUM_THREADS; 

    END { $_->join for @threads } 
} 

# enqueue the checks 
$check_q->enqueue($_) for sub {1}, sub{2}, sub{"hi"}, sub{ die }; 
$check_q->enqueue(undef) for 1..NUM_THREADS; # end the queue 

while(defined(my $result = $result_q->dequeue)) { 
    report($$result); 
} 

sub report { 
    say shift // "FAILED"; 
} 

sub worker { 
    my ($in, $out, $running_ref) = @_; 
    while (defined(my $check = $in->dequeue)) { 
    my $result = eval { $check->() }; 
    $out->enqueue(\$result); 
    } 

    # last thread closes the door 
    lock $$running_ref; 
    --$$running_ref || $out->enqueue(undef); 
} 

这将打印

1 
2 
hi 
FAILED 

在一个稍微随机顺序。