3

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 を尊重すると仮定しています。

4

1 に答える 1