パフォーマンスを最適化するために、並列処理できる部分に簡単に分割できるタスクがあります。
独立して処理できるタスクの各部分を準備するプロデューサー アクターを作成しました。この準備は比較的安価です。
それぞれの独立したタスクを処理するコンシューマー アクターを作成しました。パラメータによっては、独立したタスクの各部分の処理に数秒かかる場合があります。すべてのタスクはまったく同じです。それらはすべて同じアルゴリズムを処理し、同じ量のデータ (もちろん値は異なります) を処理するため、処理時間はほぼ同じになります。
したがって、プロデューサーはコンシューマーよりもはるかに高速です。したがって、すぐに 200 または 2000 のタスクが準備される可能性があります (パラメーターによって異なります)。それらはすべてメモリを消費しますが、一度に実行できるのはほんの数個です。
これで、タスクを使用して処理するための 2 つの単純な戦略がわかりました。
タスクごとに新しいコンシューマー アクター インスタンスを作成します。
- 各コンシューマはタスクでのみ処理します。
- 同時に多くのコンシューマー アクター インスタンスが存在すると想定していますが、一度に処理できるのはそのうちの 2 つだけです。
- デフォルトのスケジューラはどのように機能しますか? 次の消費者がスケジュールされる前に、各消費者アクターは処理を終了できますか? または、コンシューマが中断されて別のコンシューマに置き換えられ、最初のタスクが完了するまでの時間が長くなりますか? このアクターのスケジューリングは、プロセスまたはスレッドのスケジューリングと同じではないと思いますが、中断にはまだいくつかの欠点があることは想像できます (例: キャッシュ ミスが増えるなど)。
もう 1 つの戦略は、コンシューマー アクターの N インスタンスを使用し、処理するタスクをメッセージとしてそれらに送信することです。
- 各コンシューマーは、複数のタスクを順番に処理します。
- N (消費者数) の適切な値を見つけるのは私に任されています。
- N 個のコンシューマーに対するタスクの分散も私に任されています。
プロデューサーとコンシューマーの間でより多くの調整が行われる、より洗練されたソリューションを想像することもできますが、スケジューラーに関する知識がなければ、適切な決定を下すことはできません。
手動の解決策でパフォーマンスが大幅に向上しない場合は、(戦略 1 のように) スケジューリング タスクが私に任されていないデフォルトの解決策 (Scala の世界の一部によって提供される) をお勧めします。
質問のまとめ:
- デフォルトのスケジューラはどのように機能しますか?
- 次の消費者がスケジュールされる前に、各消費者アクターは処理を終了できますか?
- または、コンシューマが中断されて別のコンシューマに置き換えられ、最初のタスクが完了するまでの時間が長くなりますか?
- スケジューラーが頻繁にアクターに割り込んで別のアクターをスケジュールする場合の欠点は何ですか? キャッシュミス?
- この中断とスケジューリングは、プロセス スケジューリングまたはスレッド スケジューリングのコンテキスト変更のようなものでしょうか?
- これらの戦略を比較して、他に利点や欠点はありますか?
- 特に、戦略 1 には戦略 2 よりも不利な点がありますか?
- これらの戦略のどれが最適ですか?
- 私が提案したよりも優れた戦略はありますか?
残念ながら、最後の 2 つのような質問には絶対に答えることはできませんが、今回は可能な限り具体的なケースを挙げようとしたので、おそらくこれは可能です。
他の質問はあまり議論しなくても答えられると思います。これらの答えがあれば、要件に最適な戦略を選択できるはずです。
私は自分でいくつかの調査と考えを行い、いくつかの仮定を思いつきました。これらの仮定のいずれかが間違っている場合は、教えてください。