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

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


## コード

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

```C#
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. (本当だよ)          
     
```