web-dev-qa-db-ja.com

タスクチェーン(前のタスクが完了するのを待つ)

var tasks = new List<Task>();

foreach (var guid in guids)
{
    var task = new Task( ...);
    tasks.Add(task);
}

foreach (var task in tasks)
{
    task.Start();
    Task.WaitAll(task);
}

これはUIスレッドの実行です。タスク変数内のすべてのタスクを次々に実行する必要があります。問題は、Task.WaitAll(task)を呼び出すと、UIがフリーズすることです。 UIをフリーズせずに次のロジックを実行するにはどうすればよいですか?

16
Melursus

これはタスクチェーンではありません。

ContinueWithを使用してタスクチェーンを実行する必要があります。最後のタスクでは、UIを更新する必要があります。

_Task.Factory.StartNew( () => DoThis())
   .ContinueWith((t1) => DoThat())
   .ContinueWith((t2) => UpdateUi(), 
       TaskScheduler.FromCurrentSynchronizationContext());
_

最後の行にはTaskScheduler.FromCurrentSynchronizationContext()があります。これにより、タスクが同期コンテキスト(UIスレッド)で実行されるようになります。

31
Aliostad

最良の方法は、タスク並列ライブラリ(TPL)および継続を使用することです。 )。継続により、タスクのフローを作成できるだけでなく、例外を処理することもできます。これは すばらしい紹介 TPLの紹介です。しかし、あなたにいくつかのアイデアを与えるために...

を使用してTPLタスクを開始できます

Task task = Task.Factory.StartNew(() => 
{
    // Do some work here...
});

ここで、先行タスクが(エラーまたは正常に)終了したときに2番目のタスクを開始するには、ContinueWithメソッドを使用できます。

Task task1 = Task.Factory.StartNew(() => Console.WriteLine("Antecedant Task"));
Task task2 = task1.ContinueWith(antTask => Console.WriteLine("Continuation..."));

したがって、task1が完了するか、失敗するか、キャンセルされるとすぐにtask2 'が起動し、実行を開始します。コードの2行目に到達する前にtask1が完了した場合、task2はすぐに実行されるようにスケジュールされることに注意してください。 2番目のラムダに渡されるantTask引数は、先行タスクへの参照です。詳細な例については、 このリンク を参照してください。

先行タスクからの継続結果を渡すこともできます

Task.Factory.StartNew<int>(() => 1)
    .ContinueWith(antTask => antTask.Result * 4)
    .ContinueWith(antTask => antTask.Result * 4)
    .ContinueWith(antTask =>Console.WriteLine(antTask.Result * 4)); // Prints 64.

注意。提供された最初のリンクで例外処理を必ず読んでください。これにより、新規参入者がTPLを誤ってしまう可能性があります。

特に必要なものについて最後に確認する必要があるのは、子タスクです。子タスクは、AttachedToParentとして作成されるタスクです。この場合、すべての子タスクが完了するまで継続は実行されません

TaskCreationOptions atp = TaskCreationOptions.AttachedToParent;
Task.Factory.StartNew(() =>
{
    Task.Factory.StartNew(() => { SomeMethod() }, atp);
    Task.Factory.StartNew(() => { SomeOtherMethod() }, atp); 
}).ContinueWith( cont => { Console.WriteLine("Finished!") });

これがお役に立てば幸いです。

16
MoonKnight

継続を使用する必要があります:

lastTask.ContinueWith(() => newTask.Start());
5
SLaks