渋谷ほととぎす通信

「Unityをわかりやすく」初心者のためのゲーム作りブログ

【初心者向け】UniTaskとコルーチンの違いを理解しよう

【初心者向け】UniTaskとコルーチンの違いを理解しよう

こんにちは、Unityエンジニアのオオバです。

みなさまasync/awaitを使っていますでしょうか?Unityで非同期処理を書くなら UniTask一択 です。

オオバ
オオバ
Taskは使いづらくて・・・

正直もうコルーチンの記述には戻りたくないです。それだけコルーチンと比べて UniTaskは書きやすい んですよね。

使ってみるとわかるんですが、 UniTaskはコルーチンとまったく別物です。

UniTaskを始めてみる、またはコルーチンをUniTaskに置き換えるにしても、特性や違いを理解なしに使うと思わぬトラブルが発生 します。

【初心者向け】UniTaskとコルーチンの違いを理解しよう_0

本記事では コルーチンとUniTask(async/await)の違い について、初心者向けに解説していきます。

ぜひともUniTaskをマスターして非同期処理を気持ちよく書いてもらいたいです。

まだUniTaskを使ってない方はこちらの導入記事をどうぞ。

👉DOTweenの教科書を読んでUnityアニメーションをプログラミングしてみよう!

コルーチンとUnityタスクの違い3点

コルーチンとUniTaskは大きく3点の違いがあります。

コルーチンとUnityタスクの違い3点

①UniTaskは 戻り値の取得が可能

②UniTaskは「MonoBehaviour」がなくても実行可能

③UniTaskは「GameObject」のON/OFFで止まらない

コルーチンの面倒くさいところを解消しつつもコルーチンの方が便利だったという部分もあります。

そのあたり踏まえてUniTaskとコルーチンを比較していきます。

1.UniTaskは戻り値の取得が可能

UniTaskの大きな特徴として、タスク完了後に戻り値を取得できます。

例えば以下のようなUniTaskのコードです。

💻ソースコード : bool型を返すUniTaskサンプル
async void Start()  
{
    var result = await TestUniTask();  
    Debug.Log(result);  // true  
}

// bool型を返すUniTask  
async UniTask<bool> TestUniTask()  
{
    await UniTask.Delay(1000);  
    return true;  
}

これを従来のコルーチンで記述するとこうなります。

💻ソースコード : bool型をコールバックで返すコルーチンサンプル
IEnumerator void Start()  
{
    var result = false;  
    yield return TestCoroutine(x => result = x);  
    Debug.Log(result);  // true  
}

// bool型をコールバックで返すコルーチン  
IEnumerator TestCoroutine(Action<bool> callback)  
{
    yield return new WaitForSeconds(1f);  
    callback?.Invokd(true)  
}

サンプルコードは1つのタスク、コルーチンしか使っていないため、あまり違いを感じないかもしれません。

しかし複数定義されたらどうでしょう。コルーチンはコールバックだらけで無駄に行数が増えます。

そう考えるとUniTaskの方が 圧倒的にソースコードの見通しが良い のです。

2.UniTaskはMonoBehaviourがなくても実行可能

UniTaskは MonoBehaviour が存在しない空間でも実行可能です。例えば次のコードです。

💻ソースコード : MonoBehaviourの無い世界でUniTaskが実行されるサンプル
class TaskClass  
{
    public void ExecuteTask()  
    {
        TestTask().Forget();  
    }

    async UniTask TestTask()  
    {
        await UniTask.Delay(1000);  
        Debug.Log("UniTask完了");  
    }
}

UniTaskは MonoBehaviour が存在しなくてもUniTask、つまり非同期処理を実装できます。

コルーチンで実装するとこうなります。

💻ソースコード : コルーチンサンプル
class CoroutineClass  
{
    // コルーチンを開始させるMonoBehaviourが必要  
    public void ExecuteCoroutine(MonoBehaviour mono)  
    {
        mono.StartCoroutine(TestCoroutine())  
    }

    IEnumerator TestCoroutine()  
    {
        yield return new WaitForSeconds(1f);  
        Debug.Log("コルーチン完了");  
    }
}
  • MonoBehaviourクラスを継承する
  • MonoBehaviourインスタンスを引き渡す

以上の方法で、 コルーチンを実行するためには必ずMonoBehviourが必要 です。
この制約はパフォーマンス視点でも無駄が多いです。

UniTaskを使うと、 コルーチンを実装したいがための無駄なMonoBehaviourを撲滅。 パフォーマンスアップも期待できます。

3.UniTaskはGameObjectのON/OFFで止まらない

今までUniTaskの良いことばかりを紹介してきましたが、逆にコルーチンの方が楽だったこともあります。

UniTaskはGameObjectのON/OFFに左右されません。
具体的には以下のコードです。

💻ソースコード : GameObjectのON/OFFでUniTaskが止まらないサンプル
async void Start()  
{
    Wait5SecUniTask().Forget();  
    await UniTask.Delay(1000);  
    // 1秒後にGameObjectをOFFにしても  
    // 5秒後には"UniTask完了"はログ出力される  
    gameObject.SetActive(false);  
}

// 5秒かけて終了するUniTask  
async UniTask Wait5SecUniTask()  
{
    await UniTask.Delay(5000);  
    Debug.Log("UniTask完了");  
}

UniTaskはGameObjectとは別空間で実行されるため途中でGameObjectが比アクティブ、 Destroyされても動き続けます。

この特徴は必ず理解しておきましょう。

念の為にコルーチンに置き換えた例も紹介します。

💻ソースコード : GameObjectのON/OFFで止まるコルーチン
IEnumerator void Start()  
{
    StartCoroutine(TestCoroutine());  
    yield return new WaitForSeconds(1f);  
    gameObject.SetActive(false);  
}

// 5秒かけて終了するコルーチン  
IEnumerator Wait5SecCoroutine()  
{
    yield return new WaitForSeconds(5f);  
    Debug.Log("コルーチン完了");  
}

コルーチンの場合はGameObjectが非アクティブになった瞬間に停止するためログは出力されません。

オオバ
オオバ
この仕様に慣れているとUniTaskの置き換えに苦労するかも知れない

UniTaskの停止方法についてはこちらの記事をどうぞ。

結局UniTaskとコルーチンどっちが良いか?

オオバ的にはコルーチンはさっさと卒業すべきという考えです。つまり UniTaskに全面的に乗り換えるべき。UniTaskはUnity界ではモダンな技術。さまざまなプロダクトで採用されています。

コルーチンと比べると大幅にコード量を減らせますし、見通しのよいプログラミングになります。
今後新規でゲームを作る際にはUniTask一択という感じです。

UniTaskとコルーチンの違いのまとめ

記事の内容を簡単にまとめます。

UniTaskとコルーチンの違いのまとめ

①戻り値の取得が可能なためUniTaskはコードがスッキリする

②UniTaskはMonoBehaviourから独立した存在

③GameObjectのOFFやDestroyでUniTaskは止まらないので慣れが必要

こんな感じです。

コルーチンとの違い、特性をしっかり理解しておかないとトラブルに巻き込まれます。

「UniTaskにしたらエラーが大量にでる」 みたいな。 GameObjectのライフサイクルから独立している点 に最初は戸惑うかも知れません。

正直すぐに慣れます

何度も書いているとすぐに慣れますし、 書き味の良さ を感じられると思います。

いきなり仕事で使うにはリスクがあるかも知れないので、まずは個人プロダクトから導入してみてはいかがでしょうか。

また本記事では触れられていない便利機能がUniTaskには山程あります。

それらを触りつつ、コルーチンとの違いを体で感じつつ技術力を上げていくとよいのかなと思う次第です。

「Unity初心者大学」というUnity初心者向けのYouTube始めました!!
ぜひチャンネル登録をお願いします!

最後まで読んでいただきありがとうございました!
すばらしいUniTaskライフをお過ごしください。

オススメ記事
検証環境
  • Unity2020.3.19f1
  • UniTask v2.2.5