C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

■93833 / 親階層)  async/awaitのWaitAllの挙動について
□投稿者/ ぱっくん (1回)-(2020/02/09(Sun) 15:33:32)

分類:[C#] 

Windows 10, 日本語 (64bit)の環境でVisual Studio 2015を使用しています。

async/awaitを用いた非同期処理を始めて実装しようとしているのですが、Windowsフォームアプリケーションで作成したコードでTask.WaitAllが実行されていない?実行完了しても抜けない?問題に悩まされています。
処理が5分ほどかかる複数の処理を同時並列し、すべて終わるまで待つというコードを作成しようとしており、処理をひとつづつtaskListに格納し、Task.WaitAll(taskList.ToArray());で一度に実行することを意図しています。

まずは、成功例から。下記のコンソールアプリケーションではタスクC,D,E,F,Gを非同期で実行し、すべての処理完了後、WaitAllを抜けます。

Program.cs
            var process2 = new TestRunner();
            process2.RunTest();

TestRunner.cs
        private DoLongTimeWorkers DoWork = new DoLongTimeWorkers();

        public void RunTest()
        {
            ExecuteLongWork("[Single Task] Process A:", 5, 590, 1000);
            ExecuteLongWork("[Single Task] Process B:", 6, 690, 1000);

            var taskList = new List<Task<string>>();
            
            taskList.Add(ExecuteLongWorkAsync("[Multi Task] Process C:", 12, 990, 3000));
            taskList.Add(ExecuteLongWorkAsync("[Multi Task] Process D:", 26, 520, 8000));
            taskList.Add(ExecuteLongWorkAsync("[Multi Task] Process E:", 18, 800, 1000));
            taskList.Add(ExecuteLongWorkAsync("[Multi Task] Process F:", 21, 600, 6000));
            taskList.Add(ExecuteLongWorkAsync("[Multi Task] Process G:", 58, 200, 6000));

            Task.WaitAll(taskList.ToArray());
        }
        private async Task<string> ExecuteLongWorkAsync(string processName, int repeatTime, int intervalTime, int stableTime)
        {
            var result = await Task.Run(() => DoWork.DoLongTimeWork(processName, repeatTime, intervalTime, stableTime));

            return result;
        }
DoLongTimeWorkers.cs
    class DoLongTimeWorkers
    {
        public string DoLongTimeWork(string processName, int repeatTime, int intervalTime, int stableTime)
        {
            string result;
            for (int i = 1; i <= repeatTime; i++)
            {
                Console.WriteLine($"{processName} {i}/{repeatTime} ===== ");
                Thread.Sleep(intervalTime);
            }
            result = "Completed";
            Thread.Sleep(stableTime);


            return result;
        }

    }

上記のコードを実行するとTask AとBをシリアルに実行したあと、C-Gを同時に、非同期で実行できることが確認できます。

さて、このTestRunner.csとDoLongTimeWorkers.csを使いまわしてWindows Form Applicationに組み込だのですが、Task.WaitAll実行後処理が次に進みません。
ステップ実行する限り、Task C-Gが実行されないように見えます。Windows Form Applicationの場合になにか足りないのでしょうか。または上記コードは間違っていてたまたまConsole Applicationの場合は動いていただけなのでしょうか。

Form1.cs
        private void button1_Click(object sender, EventArgs e)
        {
            var ts = new TestRunner();
            ts.RunTest(this.textBox1);
        }
TestRunner.cs (TextBoxコントロールを渡す以外はConsole Applicationと同じ)
DoLongTimeWorkers.cs (渡されたTextBoxコントロールにConsole.WriteLineの結果を書き込む以外はConsole Applicationと同じ)

もしご存知の方がいらっしゃいましたらよろしくお願いします。

編集キー/

前の記事(元になった記事) 次の記事(この記事の返信)
親記事 →Re[1]: async/awaitのWaitAllの挙動について /Hongliang
 
上記関連ツリー

async/awaitのWaitAllの挙動について / ぱっくん (20/02/09(Sun) 15:33) #93833 ←Now
Re[1]: async/awaitのWaitAllの挙動について / Hongliang (20/02/09(Sun) 21:38) #93834
  └ Re[2]: async/awaitのWaitAllの挙動について / ぱっくん (20/02/10(Mon) 13:48) #93845 解決済み

上記ツリーを一括表示 / 上記ツリーをトピック表示
 
上記の記事へ返信