async
/を使用する場合await
、別のスレッドは必要ありません (CPU バウンド処理がないため)。
あなたの場合、非同期デリゲートのキューが必要なだけのようです。非同期デリゲートの本来の型は、Func<Task>
(戻り値なし) またはFunc<Task<T>>
(戻り値あり) です。この小さなヒントは、残念ながら現時点ではあまり知られていません。
したがって、非同期デリゲートのキューを宣言します。
private readonly Queue<Func<Task>> queue = new Queue<Func<Task>>();
次に、キューを (非同期で) 処理するだけの単一の「トップレベル」タスクを作成できます。
private Task queueProcessor;
これ以上アイテムがない場合はいつでもqueueProcessor
可能です。null
でない場合は常に、次のnull
メソッドを表します。
private async Task ProcessQueue()
{
try
{
while (queue.Count != 0)
{
Func<Task> command = queue.Dequeue();
try
{
await command();
}
catch (Exception ex)
{
// Exceptions from your queued tasks will end up here.
throw;
}
}
}
finally
{
queueProcessor = null;
}
}
メソッドEnqueue
は次のようになります。
private void Enqueue(Func<Task> command)
{
queue.Enqueue(command);
if (queueProcessor == null)
queueProcessor = ProcessQueue();
}
現在、例外処理を次のように設定しています。キューに入れられたコマンドが例外をスローすると、キュー プロセッサは処理を停止します (同じ例外が発生します)。これは、アプリケーションにとって最適な動作ではない可能性があります。
次のように使用できます (もちろん、ラムダまたは実際のメソッドのいずれかを使用)。
Enqueue(async () =>
{
ShowProgressIndicator = true;
ModelData = await myProxy.DownloadStringTaskAsync();
ShowProgressIndicator = false;
});
の使用に注意してくださいDownloadStringTaskAsync
。EAP メンバー用に TAP ラッパーを作成すると、async
コードがより「自然に見える」(つまり、より単純になる) ようになります。
これは非常に複雑なので、別のクラスに入れることをお勧めしますが、最初にエラーを処理 (および表面化) する方法を決定する必要があります。