インテル スレッディング ビルディング ブロックを使用するようにアプリのメッセージング システムを再設計しており、2 つの可能なアプローチのどちらかを決定しようとして困惑しています。
基本的に、一連のメッセージ オブジェクトと、メッセージの種類ごとに一連のハンドラーがあります。メッセージ オブジェクトごとに、そのメッセージ オブジェクトの種類に登録されている各ハンドラーを適用します。
順次バージョンは次のようになります (疑似コード):
for each message in message_sequence <- SEQUENTIAL
for each handler in (handler_table for message.type)
apply handler to message <- SEQUENTIAL
私が検討している最初のアプローチは、メッセージ オブジェクトを順番に (順次) 処理し、ハンドラーを同時に適用します。
長所:
- メッセージの予測可能な順序付け (つまり、FIFO 処理順序が保証されます)
- (潜在的に) 各メッセージの処理の待ち時間が短くなる
短所:
- 単一のメッセージ タイプのハンドラーよりも多くの処理リソースを使用できる (不適切な並列化)
- 使用するハンドラごとにメッセージ オブジェクトをコピーする必要があるため、プロセッサ キャッシュの不適切な使用
- 小さなハンドラーの大きなオーバーヘッド
このアプローチの疑似コードは次のようになります。
for each message in message_sequence <- SEQUENTIAL
parallel_for each handler in (handler_table for message.type)
apply handler to message <- PARALLEL
2 番目のアプローチは、メッセージを並行して処理し、ハンドラーを各メッセージに順番に適用することです。
長所:
- プロセッサー・キャッシュのより良い使用 (メッセージ・オブジェクトを、それを使用するすべてのハンドラーに対してローカルに保ちます)
- 小さなハンドラーは、それほど多くのオーバーヘッドを課しません (実行する他のハンドラーがある限り)
- ハンドラーよりも多くのメッセージが予想されるため、並列処理の可能性が高くなります
短所:
- 予測不可能な順序 - メッセージ A がメッセージ B の前に送信された場合、両方が同時に処理されるか、A のすべてのハンドラーが終了する前に B が処理を終了する可能性があります (順序は非決定論的です)。
擬似コードは次のとおりです。
parallel_for each message in message_sequence <- PARALLEL
for each handler in (handler_table for message.type)
apply handler to message <- SEQUENTIAL
2 番目のアプローチには、最初のアプローチよりも多くの利点がありますが、非決定論的な順序付けは大きな欠点です。
どのアプローチを選択しますか、またその理由は何ですか? 考慮すべき他のアプローチはありますか (明らかな 3 番目のアプローチ: 並列メッセージと並列ハンドラーのほかに、両方の欠点があり、実際の償還要因がないことがわかります)?
ありがとう!
編集:
私がやろうとしていることは、デフォルトで #2 を使用することだと思いますが、「会話タグ」を各メッセージに添付できるようにします。同じタグを持つすべてのメッセージは、会話に関連して順番に並べ替えられ、処理されます。ハンドラーにはメッセージと一緒に会話タグが渡されるため、必要に応じて会話を続けることができます。このようなもの:
Conversation c = new_conversation()
send_message(a, c)
...
send_message(b, c)
...
send_message(x)
handler foo (msg, conv)
send_message(z, c)
...
register_handler(foo, a.type)
a は b の前に処理され、b は z の前に処理されます。x は、a、b、z と並行して処理できます。会話内のすべてのメッセージが処理されると、会話は破棄されます。