並列拡張機能を使用して、低優先度のスレッドでシリアルにキュー型アイテムを処理する方法
-
27-09-2019 - |
質問
私は、長期にわたるプロセスの結果を連続的に処理する最良の方法を知りたいが、 .NET 4.0並列拡張機能.
両方とも実行を行い、結果を提供する次のクラスがあります。
public class Step
{
public string Name { get; set; }
public TimeSpan Duration { get; set; }
public bool Completed { get; set; }
public void Execute()
{
DateTime before = DateTime.Now;
RemotedService.DoSomeStuff();
Duration = DateTime.Now - before;
Completed = true;
}
}
これらの手順を処理し、処理後にファイルに保存するにはどうすればよいですか?しばらくファイルに保存したいのですが RemotedService.DoSomeStuff()
サーバーからの応答を待っています。
ファイルへの書き込みは次のようになります:
using (StreamWriter w = File.AppendText("myFile.txt"))
{
var completedStep = completedSteps.Dequeue();
w.WriteLine(string.Format("Completed {0} with result: {1} and duration {2}",
completedStep.Name,
completedStep.Completed,
completedStep.Duration));
}
思い浮かぶ1つの選択肢は、それらをに追加することです Queue
と Timer
それはそれらを処理します。しかし、これはリモートされた呼び出しのダウンタイムを利用しません。
頭に浮かぶ別のオプションは、次の結果を使用して各結果をファイルに非同期的に書き込むことです System.Threading.Tasks.Task
あたり Step
, 、しかし、それは彼らが順番に保存されることを保証するものではなく、またファイルへの書き込みとの競合を導入するかもしれません。
解決
作成することをお勧めします BlockingCollection<Step>
(見る System.Collections.Concurrent
名前空間)。各ステップが完了すると、そのコレクションに追加されます。のデフォルトの動作 BlockingCollection
キューとして機能するため、探しているFIFOの動作が得られます。
2番目のスレッドがキューにサービスを提供し、各アイテムを削除し、ログファイルに書き込みます。
したがって、キューを追加した場合:
static private BlockingCollection<Step> LogQueue = new BlockingCollection<Step>();
これをあなたに追加します Execute
メソッド、アイテムが完了した後:
LogQueue.Add(this);
ロギングスレッドは、静的コンストラクターで開始されます。
static void LoggingThread()
{
using (var w = new StreamWriter(...))
{
while (!LogQueue.IsCompleted())
{
Step item;
if (LogQueue.TryTake(out item))
{
w.WriteLine(....);
}
}
}
}
私が書いたときのロギングスレッドはaを使用します System.Threading
スレッド。 TPLでそれを行うには、より簡単またはより良い方法があるかもしれません。私はまだTPLにひどく精通していないので、言うことができませんでした。
他のヒント
1つのアプローチは、カスタムタスクスケジューラを作成することです(参照 http://msdn.microsoft.com/en-us/library/ee789351.aspx)。カスタムタスクスケジューラは、並行性を1回の1回に制限し、厳格な順序の実行を実施できます。
また、タスクスケジューラを作成すると、スレッドの優先度、または状況によっては望ましいアパートメンテートを制御することもできます。
あなたは文字通りワークフローファンデーションのユースケースを説明しています - それはあなたのためにこのすべてを行います:)