asyncは、一般のメソッド以外に、匿名メソッドやラムダ式に付ける場合もある。
async - C# リファレンス | Microsoft Docs
非同期メソッドの構文(2/3) - @IT
awaitを扱った時の最後のコードを見てみる。
// 名前空間の登録 using System; // 共通データ型と基本クラス(System名前空間) using System.Threading; // マルチスレッド(System.Threading名前空間) using System.Threading.Tasks; // タスク(System.Threading.Tasks名前空間) // MainClassの定義 class MainClass { // Mainの定義 static void Main() { // 実行前 Console.WriteLine("Main Begin"); // "Main Begin"と出力. // SimpleMethodを実行. SimpleMethod(); // SimpleMethodを呼ぶ. // SimpleMethodを抜けた後.(awaitで抜けた直後にここは実行される.) Console.WriteLine("SimpleMethod After"); // "SimpleMethod After"と出力. // 10秒待つ. Thread.Sleep(10000); // 10000ミリ秒休止. // 実行後 Console.WriteLine("Main End"); // "Main End"と出力. } // SimpleMethodの定義 static async void SimpleMethod() // awaitのあるメソッドにはasyncを付けないといけない. { // 実行前 Console.WriteLine("SimpleMethod Begin"); // "SimpleMethod Begin"と出力. // Task.Runで指定のActionを実行. await Task.Run(() => // awaitでこの処理を待つ. { // LongProcMethod実行前 Console.WriteLine("LongProcMethod Before"); // "LongProcMethod Before"と出力. // LongProcMethodを実行. LongProcMethod(); // LongProcMethodを呼ぶ. // LongProcMethod実行前 Console.WriteLine("LongProcMethod After"); // "LongProcMethod After"と出力. }); // 実行後(上のawaitの付いたタスクが終わるまで実行されない.) Console.WriteLine("SimpleMethod End"); // "SimpleMethod End"と出力. } // LongProcMethodの定義 static void LongProcMethod() { // 実行前 Console.WriteLine("LongProcMethod Begin"); // "LongProcMethod Begin"と出力. // 5秒休止で疑似的に長くかかる処理にする. Thread.Sleep(5000); // 5000ミリ秒休止. // 実行後 Console.WriteLine("LongProcMethod End"); // "LongProcMethod End"と出力. } }
実行すると、
最初はこう。
次はこう。
最後はこう。
LongProcMethodのThread.Sleepをawait Task.Delayにしてみる。
そうすると、LongProcMethodもasyncにしないといけない。
// 名前空間の登録 using System; // 共通データ型と基本クラス(System名前空間) using System.Threading; // マルチスレッド(System.Threading名前空間) using System.Threading.Tasks; // タスク(System.Threading.Tasks名前空間) // MainClassの定義 class MainClass { // Mainの定義 static void Main() { // 実行前 Console.WriteLine("Main Begin"); // "Main Begin"と出力. // SimpleMethodを実行. SimpleMethod(); // SimpleMethodを呼ぶ. // SimpleMethodを抜けた後.(awaitで抜けた直後にここは実行される.) Console.WriteLine("SimpleMethod After"); // "SimpleMethod After"と出力. // 10秒待つ. Thread.Sleep(10000); // 10000ミリ秒休止. // 実行後 Console.WriteLine("Main End"); // "Main End"と出力. } // SimpleMethodの定義 static async void SimpleMethod() // awaitのあるメソッドにはasyncを付けないといけない. { // 実行前 Console.WriteLine("SimpleMethod Begin"); // "SimpleMethod Begin"と出力. // Task.Runで指定のActionを実行. await Task.Run(() => // awaitでこの処理を待つ. { // LongProcMethod実行前 Console.WriteLine("LongProcMethod Before"); // "LongProcMethod Before"と出力. // LongProcMethodを実行. LongProcMethod(); // LongProcMethodを呼ぶ. // LongProcMethod実行前 Console.WriteLine("LongProcMethod After"); // "LongProcMethod After"と出力. }); // 実行後(上のawaitの付いたタスクが終わるまで実行されない.) Console.WriteLine("SimpleMethod End"); // "SimpleMethod End"と出力. } // LongProcMethodの定義 static async void LongProcMethod() // asyncにする. { // 実行前 Console.WriteLine("LongProcMethod Begin"); // "LongProcMethod Begin"と出力. // Task.Delayで5秒待つ. await Task.Delay(5000); // 5000ミリ秒待つ. // 実行後 Console.WriteLine("LongProcMethod End"); // "LongProcMethod End"と出力. } }
とすると、
最初こうなって、
次こうなって、
最後こうなる。
await Task.DelayだとLongProcMethodをすぐ抜けちゃって、"LongProcMethod After"に行ってしまい、Taskがすぐ終わって、"SimpleMethod End"まで行ってしまう。
となると、LongProcMethod自体もawaitしないといけない。
となると、ラムダ式をasyncにしないといけない。
で、こうなるわけだけど、VisualStudio2015だと、awaitする関数がvoidだとasync Taskにしないといけない。async voidにはできない。
たぶん、2013までは書けた気がするが。
C#の非同期メソッドの戻り値のvoidとかTaskがよくわからなかったので動かしてみた - Qiita
ここでも、それ言ってる。
(VS2012, VS2013準備するのも大変なので、それの検証は今回は割愛。)
で、こうすると、
こうなって、
こうなって、
こうなる。
"SimpleMethod After"以外の"~ After"や"~ End"は、長い処理が終わってから通っている。
Sample/cs/async/async/src/async at master · bg1bgst333/Sample · GitHub