1 つのオプションは、コンソール アプリケーションで処理を行うことです。あなたが持っているものは、1 つのプロデューサー (電子メールを取得するスレッド) と複数のコンシューマーによる標準的なプロデューサーとコンシューマーの問題のように見えます。これはBlockingCollectionで簡単に処理できます。
メッセージの種類 (メール サーバーから取得するもの) はMailMessage
.
したがってBlockingCollection<MailMessage>
、クラススコープで作成します。また、メッセージを収集してキューに入れるために 60 秒ごとに作動するタイマーがあると仮定します。
private BlockingCollection<MailMessage> MailMessageQueue =
new BlockingCollection<MailMessage>();
// Timer is created as a one-shot and re-initialized at each tick.
// This prevents the timer proc from being re-entered if it takes
// longer than 60 seconds to run.
System.Threading.Timer ProducerTimer = new System.Threading.Timer(
TimerProc, null, TimeSpan.FromSeconds(60), TimeSpan.FromMilliseconds(-1));
void TimerProc(object state)
{
var newMessages = GetMessagesFromServer();
foreach (var msg in newMessages)
{
MailMessageQueue.Add(msg);
}
ProducerTimer.Change(TimeSpan.FromSeconds(60), TimeSpan.FromMilliseconds(-1));
}
コンシューマー スレッドはキューを読み取るだけです。
void MessageProcessor()
{
foreach (var msg in MailMessageQueue.GetConsumingEnumerable())
{
ProcessMessage();
}
}
タイマーにより、プロデューサーは 1 分に 1 回実行されます。コンシューマーを開始するには (2 つ欲しいとします):
var t1 = Task.Factory.StartNew(MessageProcessor, TaskCreationOptions.LongRunning);
var t2 = Task.Factory.StartNew(MessageProcessor, TaskCreationOptions.LongRunning);
したがって、2 つのスレッドでメッセージを処理することになります。
使用可能な CPU コアより多くの処理スレッドを使用しても意味がありません。プロデューサー スレッドはおそらく多くの CPU リソースを必要としないため、専用のスレッドを作成する必要はありません。処理を行っているときはいつでも、メッセージの処理が一時的に遅くなるだけです。
上記の説明の詳細、特にスレッドのキャンセルについては省略しました。プログラムを停止したいが、コンシューマにメッセージの処理を終了させたい場合は、プロデューサ タイマーを強制終了し、追加のためにキューを完了として設定します。
MailMessageQueue.CompleteAdding();
コンシューマーはキューを空にして終了します。もちろん、タスクが完了するまで待ちます (「 」を参照Task.Wait
)。
キューを空にすることなくコンシューマーを強制終了する機能が必要な場合は、 Cancellationを調べる必要があります。
のデフォルトのバッキング ストアBlockingCollection
はConcurrentQueue
、厳密な FIFO です。物事に優先順位を付けたい場合は、IProducerConsumerCollectionインターフェイスを実装する同時優先キューを考え出す必要があります。.NET にはそのようなもの (または優先度キュー クラス) はありませんが、同時アクセスを防ぐためにロックを使用する単純なバイナリ ヒープで十分です。あなたはこれを非常に強く打つことについて話しているのではありません。
もちろん、メッセージに優先順位を付ける何らかの方法が必要です。おそらく、添付ファイルのないメッセージがより迅速に処理されるように、添付ファイルの数で並べ替えます。もう 1 つのオプションは、2 つの別個のキューを用意することです。1 つは添付ファイルが 0 または 1 個のメッセージ用で、もう 1 つは多数の添付ファイルがあるメッセージ用です。簡単なメッセージが常に最初に処理される可能性が高くなるように、コンシューマーの 1 つを 0 または 1 キュー専用にすることができます。他のコンシューマーは、空でない限り 0 または 1 キューから受け取り、次に他のキューから受け取ります。 . 消費者はもう少し複雑になりますが、それほど複雑ではありません。
メッセージ処理を別のプログラムに移動することを選択した場合は、プロデューサーからコンシューマーにデータを永続化する何らかの方法が必要になります。それを行うには多くの可能な方法がありますが、私はそれの利点がわかりません。