並行システムで発生する問題の解決策を見つけるのに苦労しています(現在はアクターモデルを使用しています)。私は基本的に俳優のダイヤモンド構造を持っています:
したがって、D
はC
とB
にメッセージを送信し、その結果、A
にメッセージを送信します。各部分は、メッセージを受信すると、なんらかの形式の操作を実行します。
例として、次のようないくつかの任意の操作を定義します。
C
、B
の結果ですA
がその操作を適用した後、結果を公開します。 A
からの特定のメッセージに対してB
とC
の両方から結果を受け取った場合にのみ、D
に結果を公開させたいと思います。したがって、増分インデックスiがあり、数値x_iを生成する場合、A
がc_k、b_j(k == jの場合)でのみ動作するようにします。
この問題をかなり難しくしている私のシステムの1つの特性は、スロットルの存在です。操作にコストがかかるか、D
がメッセージを送信する頻度が高くなる可能性があるため、キューが無限に大きくなるのを防ぐために、これが必要と思われます。これにより、「メッセージをD
からマークし、同じマークのメッセージを2つ受信した場合にのみ、A
で実行する」という形式のソリューションが排除されるように思われます。これら2つのメッセージを受信することを保証します。
この分野での私の経験はかなり限られているので、このような同様の問題を扱うリソースやパターンがあれば役に立ちます。
航空宇宙産業では、IRIG 106 Chapter 10と呼ばれるファイル形式があります。これは、マルチチャネルパケットメタファを使用します。チャネルの1つには、指示対象として使用されるTimeパケットが含まれています。
第10章の興味深い機能の1つは、(TCP/IPと同様に)パケットが任意の順序で到着できることです。パケットにはシーケンス番号が含まれているため、正しい順序で再構成できますが、時間をロックしようとしていて、タイムパケットが期待どおりにデータストリームに到着しない場合は、次のことを行う必要があります。データをバッファリングし、到着するまで待ちます。
単に存在しないタイムパケットの問題を回避するために、第10章の仕様では、タイムパケットが表す時間と、タイムパケットが第10章のファイルに書き込まれるまでの遅延は1秒を超えてはならないことが規定されています。これにより、第10章のファイルを処理するデータ処理装置は、標準に準拠したまま、最大1秒のデータをバッファリングするだけで済むようにシステムを設計できます。また、データレコーダーは、タイムパケットが期限切れになった後、1秒以上経過しないように設計する必要があります。
システムには、これに似たある種の設計上の制約と、その非準拠を処理する方法が必要なようです。
この種のモデルを処理する最も自然で同時の方法は、BとDの両方にインバウンドキューとアウトバウンドキューを構築し、Aに2つのインバウンドキュー(および結果の使用方法によってはAにアウトバウンドキュー)を構築することです。
スロットリングを確実にする簡単な方法は、BおよびCに送信キューの最大長を設定し、送信キューが構成された値を超えた場合にそれらを一時停止することです。値1はささいなキューですが、より複雑な状況では、各計算の実行時間は変化するか、予測が難しい場合があります。
したがって、Cが後で複雑なケースを受け取り、Bに小さなタスクが与えられた場合に備えて、Bが長い計算を実行している間に、(たとえば)Cがいくつかの結果をキューに入れることは理にかなっています。
したがって、最も単純なAは、1つのキューを調べ、何かが見つかった場合は他のキューを調べ、他のキューを待機します。何かがあると、他のキューを見てそこで待機します。両方のキューに何かがある場合、処理を続行します。
「グロス」遅延(時間によって定義されるか、一方または他方でnメッセージ遅れることによって定義される)に対処する1つの方法は、Aがキューの1つにあるエントリを破棄し、他のプロセッサに前方にスキップするように通知することです。これには、キュー間の再同期が少し含まれます。
この種のアプローチは有効である可能性があり、アニメーションでフレームをドロップするのと少し似ています。
パケットの「損失を同期化」する何らかの方法が必要です。最悪のシナリオでは、B
はすべての偶数パケットを失い、C
はすべての奇数パケットを失う可能性があるため、A
は結果を生成できなくなります。
そのような同期の概念を簡単な例で説明します。 A
がメッセージを生成したとき、まだメッセージを送信していません。代わりに、それをいくつかのフィールドに格納します。 B
とC
の両方がD
に新しいメッセージを受信する準備ができていることを通知した後でのみ、D
はこの保存されたメッセージをB
およびC
。 B
とC
がタスクを終了した後、A
にはD
からの同じ元のメッセージに対応するデータがいくつかあります。
保存されたメッセージが送信される前にA
が新しいメッセージを生成した場合、以前に保存されたメッセージは上書きされて失われます。もう1つの制約は、メッセージレシーバーB
およびC
がD
に登録され、D
に準備ができていること、つまりより緊密な結合が必要であることを通知する必要があることです。 。
もちろん、中間ストレージの概念は、D
がメッセージをすぐに中間に送信し、次にメッセージをB
に送信するように、独自のクラスにリファクタリングすることができます。必要に応じてC
。