次の状況を考慮してください。
同じカテゴリの複数のジョブが同時に処理される可能性があるため、この状況では従来のキューは機能しませんが、これは許可されていません。
取得するジョブをワーカーに確認させ、そのジョブカテゴリに現在処理中の別のワーカーがあるかどうかを確認し、その場合は後で処理するためにジョブをキューに再送信します。これは、この問題を解決する非効率的な方法のようです。この問題を解決できるデータ構造または設計パターンはありますか?
さらに説明が必要な場合は、お知らせください。
この問題には2つの部分があります。
1つ:可能なカテゴリの不明なリスト。
2つ:同じカテゴリの2つのジョブが同時に処理されるのを防ぐための、ワーカー間のプロセス間通信。
カテゴリの既知のリストがある場合は、カテゴリごとに1つのキューと1つのワーカーを持つことができます。
カテゴリが不明な場合でも、カテゴリごとにキューを設定できますが、カテゴリごとにキューワーカーがある場合は、すべてのキューを監視し、新しいカテゴリが表示されたときに新しいワーカーを起動する必要があります。
これは、仕事を配る「マスター」ワーカーで達成できます
すべてのジョブは「マスター」キューに入れられます。
カテゴリワーカーはプライベートキューを作成し、作業に使用できるようにマスターに登録します。
マスターワーカーはジョブを取得し、カテゴリをチェックし、利用可能なワーカーをチェックし、プライベートキューに入れることにより、ジョブの1つに割り当てます。
マスターは、ワーカーに割り当てられたカテゴリを追跡できます。
マスターは次のジョブをピックアップしますが、同じカテゴリであり、ワーカーはまだビジーであるため、ジョブをカテゴリ固有の保留キューに入れます
マスターは次のジョブを取得します。その新しいカテゴリーは、別のカテゴリーワーカーに割り当てます。
カテゴリーワーカーはジョブを完了し、作業に再登録します
マスターは保留キューとマスターキューの次のジョブをチェックし、使用可能なカテゴリワーカーに割り当てます。
カテゴリワーカーがジョブ中にクラッシュした場合、再登録されません。そのため、マスターは、タイムアウトロジックを使用して、あきらめて、別のワーカーにカテゴリを割り当て始めることができます。
また、常にマスターワーカーが1人だけになるように注意する必要があります。これは、何らかのマスターキューの排他ロックを必要とします
あなたの非効率的な提案の欠点は、カテゴリに2つのジョブがある場合です。今、一人は働いています。そして、他の皆は忙しい待機をしています。
これを十分に行うには、ワーカーにキューをスキャンして次の実行可能なタスクをスキャンさせ、見つかった場合はそれ以外のすべてをキューに返します。代わりにすべてを返し、次にスリープします。スリープにランダム性と指数バックオフがある場合、「ビジー待機」はビジーではありません。
より効率的なアプローチのために、仕事をつかむ労働者は、そのカテゴリーから他に何もすることがなくなるまで、そのカテゴリーを行う責任があります。次に、正規労働者に戻ります。しかし、いくつかの微妙な点があります。
これらを確認するために、try
およびrelease
ロック(両方とも非ブロッキング)が可能であり、キュー操作がadd
、get
および_is_empty
_ get
はブロックおよび待機操作です。
一般的なキューを想定し、次に各カテゴリに対してキューとロックを想定します。
基本的なワーカーフローは次のとおりです。
_while obj = get from main queue:
if try category lock:
do obj job
do_whole_category_queue()
else:
add obj to category queue
if try category lock:
do_whole_category_queue()
_
どこ
_procedure do_whole_category_queue
while not category queue is_empty:
obj = get from category queue
do obj job
release category lock
if not is_empty category queue:
if try category lock:
do_whole_category_queue()
_
ここでの注意深いロックハンドシェイクに注意してください。ワーカーはロックをテストし、ロックされている場合はジョブをキューに追加します。ただし、ロックを再度テストして、実際にジョブを実行するのがまだ他の誰かの責任であることを確認する必要があります。キューの操作中にカテゴリワーカーが終了した場合に備えて。
(これは、人々がしばしば失敗する、ロックの詳細の一種です。エラーは確実に再現することは不可能ですが、本番環境では無作為かつ不可解にねじ込まれます...)