3
2

More than 5 years have passed since last update.

C# Task,async,awaitを一気に実行して比較する

Posted at

はじめに

この記事は、@acple@github さんによって書かれた記事のまとめというか焼き直しになります。
要は下記の記事に出てきたプログラムを全部まとめて実行するコードを書いた(そしたら見やすかった→記事にした)というだけの話で、詳細な解説は書きません。
ぜひとも下記リンク先の記事を読んで、なんとなく雰囲気をつかんでから実行してみてださい。
https://qiita.com/acple@github/items/8f63aacb13de9954c5da

コード

(C# .NETFramework,Version=v4.5.2 コンソールアプリケーションで動作確認済)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TaskAndThread
{
    class Program
    {
        static void Main(string[] args)
        {
            Parts p = new Parts();

            p.RunHeavyMethodSync();

            p.RunHeavyMethodAsync1();  // 警告出るけどシカトでok

            p.RunHeavyMethodAsync2();

            p.RunHeavyMethodParallel1();

            p.RunHeavyMethodParallel2();            // waitなし
            //p.RunHeavyMethodParallel2().Wait();   // waitあり 両者で比較してみてください。

            p.KusoMethod();


            Console.WriteLine("Press any key to quit. (うそです) ");    // 先に出る

            System.Threading.Thread.Sleep(8000);                        // Mainスレッドにsleepをかけている       
            Console.WriteLine("Press any key to quit. (本当だよ) ");    // ↑のsleepをコメントにすると、当然この行も先に出る

            Console.Read();
        }
    }


    class Parts
    {
        // 現実のプログラミングではここが重い処理になる。今回はsleepで代用
        private void HeavyMethod(int x, string refMethod)
        {
            Thread.Sleep(5 * (100 - x)); // てきとーに時間を潰す
            Console.WriteLine(refMethod + " : " + x);
        }


        // 比較のため、ただの同期メソッド
        public void RunHeavyMethodSync() 
        {
            for (var i = 0; i < 10; i++)
            {
                var x = i;
                HeavyMethod(x, "HM ");
            }
        }
        // -------------------------------------


        // 「HeavyMethodを実行する」というタスクを開始し、完了するまで待機を
        //  10回繰り返すというタスクを表すので、これは順次動作であり、並列ではない。
        public async Task RunHeavyMethodAsync1()
        {
            for (var i = 0; i < 10; i++)
            {
                var x = i;
                await Task.Run(() => HeavyMethod(x, "HM1")); 
            }                                               
        }
        // -------------------------------------


        // 動作はRunHeavyMethodAsync1と同じだけど、
        // HeavyMethodの実行がいつ完了するのか知ることができない。つらい。
        //
        public async void RunHeavyMethodAsync2() // RunHeavyMethodAsync1の戻り値がvoidになっただけ
        {
            for (var i = 0; i < 10; i++)
            {
                var x = i;
                await Task.Run(() => HeavyMethod(x, "HM2"));
            }
        }
        // -------------------------------------


        // HeavyMethodを開始せよという命令を、10回繰り返すだけなので、
        // これは並列動作になる。Task.Runが投げっぱなしなので、HeavyMethodの状態がわからなくてつらい。
        //
        public void RunHeavyMethodParallel1() // asyncじゃない
        {
            for (var i = 0; i < 10; i++)
            {
                var x = i;
                Task.Run(() => HeavyMethod(x, "HP1"));
            }
        }
        // -------------------------------------



        // 全てのTaskが完了した時に完了扱いになるたった一つのTaskを作成
        // 非同期メソッドではないが、戻り値がTaskなのでこのメソッドは一つのタスクを表しているといえる。
        //
        public Task RunHeavyMethodParallel2()                      // asyncじゃないけど、戻り値がTask
        {
            var tasks = new List<Task>();                          // TaskをまとめるListを作成
            for (var i = 0; i < 10; i++)
            {
                var x = i;
                var task = Task.Run(() => HeavyMethod(x, "HP2"));  // HeavyMethodを開始するというTask
                tasks.Add(task);                                   // を、Listにまとめる
            }
            return Task.WhenAll(tasks);
        }
        // -------------------------------------



        // デッドロックを回避するサンプル  ------
        public void KusoMethod()
        {
            NiceAsyncMethod().Wait(); // Waitしてもデッドロックしない!
            Console.WriteLine("I am KusoMethod()");
        }


        private async Task NiceAsyncMethod()
        {
            await Task.Delay(1000).ConfigureAwait(false);  // ←重要
        }
        // -------------------------------------


    }
}

実行結果

HM  : 0
HM  : 1
HM  : 2
HM  : 3
HM  : 4
HM  : 5
HM  : 6
HM  : 7
HM  : 8
HM  : 9
HP1 : 1
HM1 : 0
HM2 : 0
HP1 : 0
HP1 : 3
HP1 : 2
HM2 : 1
HM1 : 1
HP1 : 5
I am KusoMethod()
Press any key to quit. (うそです)
HP1 : 4
HM2 : 2
HM1 : 2
HP1 : 7
HP1 : 6
HM2 : 3
HM1 : 3
HP1 : 9
HP1 : 8
HM2 : 4
HM1 : 4
HP2 : 1
HP2 : 0
HM2 : 5
HM1 : 5
HP2 : 4
HP2 : 3
HP2 : 2
HM1 : 6
HM2 : 6
HP2 : 7
HP2 : 6
HP2 : 5
HM1 : 7
HM2 : 7
HP2 : 9
HP2 : 8
HM2 : 8
HM1 : 8
HM2 : 9
HM1 : 9
Press any key to quit. (本当だよ)          

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2