C#での非同期処理(Task、async/await)

#ゆーじ勉強週間 4日目の記事です。

これまでの記事はこちら

 

今日の勉強テーマ

今日の勉強テーマは、「非同期処理」です。

勉強したことのメモのような感覚なので、上手くまとまってなかったりいろいろ飛ばしたりしてますがご了承ください。

 

こちらのサイトを参考にしました。
https://tech-lab.sios.jp/archives/15637
https://qiita.com/acple@github/items/8f63aacb13de9954c5da

スレッド

スレッド処理の一連の流れ
シングルスレッド処理の流れが一本道
マルチスレッド複数の処理の流れを並行して行う

ThreadとTask

Threadはレガシーなものなので、特に理由がなければTaskを使えば良い。

Taskの非同期処理

static void Main()
{
    // Task.Run()を使うと別スレッドで実行される
    // delegateを引数にとる
    Task task = Task.Run(() => {
        HeavyMethod1();
    }); 
 
    HeavyMethod2();
}   
 
static void HeavyMethod1()
{   
    Console.WriteLine("HeavyMethod1 Start"); 
    Thread.Sleep(5000);
    Console.WriteLine("HeavyMethod1 End"); 
}   
 
static void HeavyMethod2()
{   
    Console.WriteLine("HeavyMethod2 Start"); 
    Thread.Sleep(3000);
    Console.WriteLine("HeavyMethod2 End"); 
} 

この場合、

HeavyMethod2 Start
HeavyMethod2 End
HeavyMethod1 Start
HeavyMethod1 End

という出力結果になる。

Taskで結果を待機

static void Main(string[] args)
{
    // 結果を受け取る場合はTask型の変数に入れ、結果を戻り値で返す(戻り値の型はT)
    Task task = Task.Run(() => {
        return HeavyMethod();
    }); 
 
    // ResultプロパティでTaskの完了まで待機してから結果を返す
    string result = task.Result;
 
    Console.WriteLine(result); // resultにちゃんと結果が入ってる
}   
 
static string HeavyMethod()
{   
    Console.WriteLine("HeavyMethod Start"); 
    Thread.Sleep(5000);
    Console.WriteLine("HeavyMethod End"); 
 
    return "hoge";
}   

この場合、

HeavyMethod Start
HeavyMethod End
hoge

という出力結果になる。

async/await

async/awaitとは、同期処理を書くような感覚で非同期処理を書くことができる魔法の言葉。

 

【ポイント】

  • 非同期メソッドには修飾子asyncをつけて、戻り値はTask型またはTask型のジェネリックにする
  • asyncをつけた非同期メソッド内ではawaitを使える
  • awaitは戻り値がTask型のメソッドにしかつけられない(Task.Run()やTask.Delay()など)
  • awaitをつけると、そのメソッドの処理が完了するまで待ってくれる(それより先に進まない)
  • awaitがついたメソッドの完了を待っている間は、awaitが存在するメソッド(asyncがついたメソッド)はいったん抜ける

同期メソッドと非同期メソッドの比較

 戻り値なし戻り値あり
同期メソッドvoid Method(){ }T Method(){ return T }
非同期メソッドasync Task Method(){ }async Task Method(){ return Task }

「async void」はわざわざ使う必要ない。(UIのイベントハンドラ用)
せっかくTask型を返して処理状況が確認できるようになっているので、使っておけば良い。

awaitをつけるか否か

「Task.Run(処理)」は、「この処理誰かやっといて!(自分はもとの作業をやる)」
「await Task.Run(処理)」は、「この処理やるから終わるまでちょっと待って!」

Unityで使うには

Task、async/awaitはUnityだと「.NET4.x」にすれば使える。
(PlayerSettingsのOtherSettings内で指定するところがある)

まとめ

非同期処理難しいですね。

明日はUniRxの勉強をしたい気持ちですが、実家に帰るので時間が取れるか微妙。

コメント