C# async/await の非同期性をテストしていて、ContinueWith の後続のコードが前のタスクの完了を待たないという驚きに遭遇しました。
public async Task<int> SampleAsyncMethodAsync(int number,string id)
{
Console.WriteLine($"Started work for {id}.{number}");
ConcurrentBag<int> abc = new ConcurrentBag<int>();
await Task.Run(() => { for (int count = 0; count < 30; count++) { Console.WriteLine($"[{id}] Run: {number}"); abc.Add(count); } });
Console.WriteLine($"Completed work for {id}.{number}");
return abc.Sum();
}
以下のテストメソッドで実行されます。
[Test]
public void TestAsyncWaitForPreviousTask()
{
for (int count = 0; count < 3; count++)
{
int scopeCount = count;
var c = SampleAsyncMethodAsync(0, scopeCount.ToString())
.ContinueWith((prevTask) =>
{
return SampleAsyncMethodAsync(1, scopeCount.ToString());
})
.ContinueWith((prevTask2) =>
{
return SampleAsyncMethodAsync(2, scopeCount.ToString());
});
}
}
出力は、run 0.0、1.0、および 2.0 の実行が非同期で正しく実行されることを示していますが、後続の x.1 および x.2 はほぼすぐに開始され、x.2 は x.1 の前に実際に完了します。以下に記録されている例:
[2] Run: 0
[2] Run: 0
[2] Run: 0
Completed work for 2.0
Started work for 0.1
Started work for 0.2 <-- surprise!
[0] Run: 2
[0] Run: 2
[0] Run: 2
[0] Run: 2
[0] Run: 2
continueWith は、後続のチェーンに関係なく、最初のタスク (0) でのみ待機するようです。この問題は、最初の Continuewith ブロック内に 2 番目の ContinueWith を入れ子にすることで解決できます。
私のコードに何か問題がありますか? Console.WriteLine が FIFO を尊重すると仮定しています。