2013-06-26 114 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 

在一個稍微隨機順序。