これは確かに解決できる方法がいくつかあり、そのうちの1つはあなたのものです。しかし、特に同期待機(Thread.Sleep)以外の何もしない場合、長時間実行するタスクを開始することは、実際には良い習慣ではありません。
テクニカルとドメインの部分でコードをリファクタリングすることを検討する必要があります。技術的な部分がある:
- まで待つことに時間がかかる場合は、指定されたコレクション内のすべてのタスクが
- を完了するまで定期的に進捗状況は次のコードは、このビットよりよく理解するために役立つかもしれない
を報告します。これは、異なる非同期操作をシミュレートし、それらがすべて完了するのを待つ4つのタスクを開始します。これが250msより長くかかる場合、WhenAllExの呼び出しは、進捗報告を再発行するためにラムダを呼び出すことを継続する。
static void Main(string[] args)
{
var tasks = Enumerable.Range(0, 4).Select(taskNumber => Task.Run(async() =>
{
Console.WriteLine("Task {0} starting", taskNumber);
await Task.Delay((taskNumber + 1) * 1000);
Console.WriteLine("Task {0} stopping", taskNumber);
})).ToList();
// Wait for all tasks to complete and do progress report
var whenAll = WhenAllEx(
tasks,
_ => Console.WriteLine("Still in progress. ({0}/{1} completed)", _.Count(task => task.IsCompleted), tasks.Count()));
// Usually never wait for asynchronous operations unless your in Main
whenAll.Wait();
Console.WriteLine("All tasks finished");
Console.ReadKey();
}
/// <summary>
/// Takes a collection of tasks and completes the returned task when all tasks have completed. If completion
/// takes a while a progress lambda is called where all tasks can be observed for their status.
/// </summary>
/// <param name="tasks"></param>
/// <param name="reportProgressAction"></param>
/// <returns></returns>
public static async Task WhenAllEx(ICollection<Task> tasks, Action<ICollection<Task>> reportProgressAction)
{
// get Task which completes when all 'tasks' have completed
var whenAllTask = Task.WhenAll(tasks);
for (; ;)
{
// get Task which completes after 250ms
var timer = Task.Delay(250); // you might want to make this configurable
// Wait until either all tasks have completed OR 250ms passed
await Task.WhenAny(whenAllTask, timer);
// if all tasks have completed, complete the returned task
if (whenAllTask.IsCompleted)
{
return;
}
// Otherwise call progress report lambda and do another round
reportProgressAction(tasks);
}
}
この行は "var whenAllTask = Task.WhenAll(tasks);"すべてのタスクが完了するまでブロックされますか?コードは常にすべてのタスクが完了するのを待ってからTask.Delayを実行しますか? –
Task.WhenAll(...)はブロックしませんが、パラメータ内のすべてのタスクが完了すると完了するタスクを返します。 Task.Delayも同様です。 250ms後に完了するタスクを返します(サンプルコード内)。トリックは、Task.WhenAllまたはTask.Delayが完了したときに完了する3番目のタスクを待つことです。私はコードにいくつかのコメントを追加します。 –
お返事ありがとうございました!私は2つの構文の質問があります。 'var whenAll'のためのパラメータで使ったアンダースコアで構文上何が起きているのですか?' for(;;) 'の構文で何が起こっていますか? – cloudcrypt