7

私は、さまざまなサービス、システム、データベース、ファイルなどに対してさまざまな「チェック」を実行する「チェッカー」システムを作成してきました。「チェック」は本質的に一般的であり、何でもかまいません。すべてのチェックは、合格または不合格にかかわらず、共通の形式で報告されます。

モジュラー 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 などの特定のウォッチャーがあります。特定のものは必要ありません。非同期タスクが何であれ、単純に開始し、すべてのタスクが完了したら通知するだけで次に進むことができるイベント ベースのモデルが必要です。

うまくいけば、それがそれを説明し、あなたは私を正しい方向に向けることができます.

4

1 に答える 1

6

これは、上司と従業員のモデルに適しているようです。

  • プログラムの開始時にいくつかのワーカーを生成します。全員がキューにアクセスできることを確認してください。

  • 好きなだけチェックをキューに入れます。ワーカーはチェックをデキューして実行し、結果を出力キューに入れます。

  • メインスレッドは、出力スレッドからの結果を見て、必要なことを何でもします。

  • 労働者をENDブロックに参加させる

Thread::Queue::Anycoderef をキューに入れる可能性があるかどうかを調べたいと思うでしょう。

完全に実行可能な例を次に示します。

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

少しランダムな順序で。

于 2013-06-26T16:31:09.117 に答える