私は、いくつかのタスクを並行して実行し、それらの中のいくつかが終了してから処理を続けるという少し複雑な要件があります。さて、私は、私が並行して実行したいが、ContinueWithハンドラの中にいくつかのタスクがあるとき、予期せぬ動作に遭遇しています。私はこの問題を説明するために少量のサンプルを泡立てた:ContinueWithブロック内で予期せぬ動作が発生する
var task1 = Task.Factory.StartNew(() =>
{
Console.WriteLine("11");
Thread.Sleep(1000);
Console.WriteLine("12");
}).ContinueWith(async t =>
{
Console.WriteLine("13");
var innerTasks = new List<Task>();
for (var i = 0; i < 10; i++)
{
var j = i;
innerTasks.Add(Task.Factory.StartNew(() =>
{
Console.WriteLine("1_" + j + "_1");
Thread.Sleep(500);
Console.WriteLine("1_" + j + "_2");
}));
}
await Task.WhenAll(innerTasks.ToArray());
//Task.WaitAll(innerTasks.ToArray());
Thread.Sleep(1000);
Console.WriteLine("14");
});
var task2 = Task.Factory.StartNew(() =>
{
Console.WriteLine("21");
Thread.Sleep(1000);
Console.WriteLine("22");
}).ContinueWith(t =>
{
Console.WriteLine("23");
Thread.Sleep(1000);
Console.WriteLine("24");
});
Console.WriteLine("1");
await Task.WhenAll(task1, task2);
Console.WriteLine("2");
基本的なパターンである。 - タスク1、タスク2 と並行して実行されるべきである - パート1の最初の部分が完了したら、それは並行していくつかのことを行う必要があります。私はすべてが完了したら、完了したい。
1 <- Start
11/21 <- The initial task start
12/22 <- The initial task end
13/23 <- The continuation task start
Some combinations of "1_[0..9]_[1..2]" and 24 <- the "inner" tasks of task 1 + the continuation of task 2 end
14 <- The end of the task 1 continuation
2 <- The end
代わりに、何が起こるか、await Task.WhenAll(innerTasks.ToArray());
はない「ブロック」完成から継続タスクないことである:
は、私は次のような結果を期待しています。したがって、外側のタスクは、外側のawait Task.WhenAll(task1, task2);
が完了した後に実行されます。結果のようなものです:
1 <- Start
11/21 <- The initial task start
12/22 <- The initial task end
13/23 <- The continuation task start
Some combinations of "1_[0..9]_[1..2]" and 24 <- the "inner" tasks of task 1 + the continuation of task 2 end
2 <- The end
Some more combinations of "1_[0..9]_[1..2]" <- the "inner" tasks of task 1
14 <- The end of the task 1 continuation
場合は、代わりに、私はTask.WaitAll(innerTasks.ToArray())
を使用し、すべてが期待通りに動作するようです。もちろん、WaitAllを使用したくないので、スレッドをブロックしません。
私の質問は以下のとおりです。
は- は、なぜ、この予期しない動作が発生していますか?
- どのようにスレッドをブロックすることなく状況を改善できますか?
ありがとうございました!
質問1への回答は、ContinueWithがその内容を非同期で実行し、何も待っていないためです。あなたはtask1を待っていますが、continueWithはその一部ではありません。 – user1676075
希望の結果を得るために、「continueWith」パーツをtask1のインラインで(continueWithではなく)インライン化したいと思うようです。それは本当にあなたが言っていることです。タスク1でこれらのステップを実行し、次にこれらのタスクを実行します。それはcontinueWithを必要としません。 – user1676075
インライン化は実際にはオプションではありません。最初のタスクは既に非同期なので、継続が実行される前に完了する必要があるからです。私はもちろん、ラッピングタスクを使用することができ、その中で、最初の操作を待ってから、他の操作を待ちます。しかし、私は十分なはずだと思うところで2つの仕事をするでしょう。一方、 'ContinueWith'は' Task 'を返すことでそれをやっているようですので、余分なタスクがどこから来るかは問題ではないと思います。私が間違っているなら、私を修正してください。 –