Unityに関連する記事です

 最初に覚える非同期処理についてはコルーチンがあります。
とても便利な処理ですが、UniTask という別の非同期処理も用意されてます。

 両方の使い方を理解することで、上手に使い分けていくことが出来ますので、
ここでは、これから UniTask を覚えていきたい方向けに処理を比較して、置き換えながら UniTask を学習します。

 なお、「そもそも UniTask とは?」という部分については触れません。

 UniTask を学習してみたいけど、どのように実装していいのか、導入の糸口が見当たらないという方を対象としています。



1.非同期処理の違い


 非同期処理について、処理を比較し、違いを見ながら学習しましょう。


1.コルーチン


 コルーチンをスタートし、時間の経過に合わせてログを表示します。

using System.Collections;
using UnityEngine;

public class CoroutineExample : MonoBehaviour
{
    private void Start()
    {
        StartCoroutine(MyCoroutine());
    }

    private IEnumerator MyCoroutine()
    {
        Debug.Log("Coroutine Started");
        yield return new WaitForSeconds(2.0f);
        Debug.Log("Coroutine Finished");
    }
}


2.UniTask


 ここでは先ほどのコルーチンの処理を UniTask を利用して置き換えた場合の実装例です。

using Cysharp.Threading.Tasks;
using UnityEngine;

public class UniTaskExample : MonoBehaviour
{
    private async void Start()
    {
        Debug.Log("UniTask Started");
        await UniTask.Delay(TimeSpan.FromSeconds(2));
        Debug.Log("UniTask Finished");
    }
}


3.処理の書き方の比較


 非同期処理について、コルーチンと UniTask を、書き方で比較してみましょう。
先にコルーチンの処理を提示し、その後、同じ内容を UniTask で作成しています。


using System.Collections;
using UnityEngine;

public class CoroutineExample : MonoBehaviour
{
    private void Start()
    {
        StartCoroutine(MyCoroutine());
    }

    private IEnumerator MyCoroutine()
    {
        Debug.Log("Coroutine Started");
        yield return new WaitForSeconds(2.0f);
        Debug.Log("Waited for 2 seconds in Coroutine");
        
        yield return new WaitForEndOfFrame(); // 現在のフレームの終了を待つ
        Debug.Log("Waited for EndOfFrame in Coroutine");
        
        yield return new WaitForFixedUpdate(); // 次のFixedUpdateを待つ
        Debug.Log("Waited for FixedUpdate in Coroutine");
        
        yield return new WaitUntil(() => Input.GetKeyDown(KeyCode.Space)); // 条件が満たされるまで待つ
        Debug.Log("Waited until Space key is pressed in Coroutine");
        
        yield return null; // 1フレーム待機
        Debug.Log("Waited for 1 frame in Coroutine");
    }
}



 ここからは UniTask の場合です。


using Cysharp.Threading.Tasks;
using UnityEngine;

public class UniTaskExample : MonoBehaviour
{
    private async void Start()
    {
        Debug.Log("UniTask Started");
        await UniTask.Delay(TimeSpan.FromSeconds(2));
        Debug.Log("Waited for 2 seconds in UniTask");
        
        await UniTask.NextFrame(); // 現在のフレームの終了を待つ
        Debug.Log("Waited for EndOfFrame in UniTask");
        
        await UniTask.WaitForFixedUpdate(); // 次のFixedUpdateを待つ
        Debug.Log("Waited for FixedUpdate in UniTask");
        
        await UniTask.WaitUntil(() => Input.GetKeyDown(KeyCode.Space)); // 条件が満たされるまで待つ
        Debug.Log("Waited until Space key is pressed in UniTask");
        
        await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); // 1フレーム待機
        Debug.Log("Waited for 1 frame in UniTask");
    }
}

 どちらも同じように非同期処理が作成できます。


4.ポイント

 
 コルーチンとUniTaskの非同期処理には、書き方だけでなく、いくつかの重要な違いが存在します。

 以下に、それらの違いをまとめます。


1.戻り値の違い

 <コルーチン>

  コルーチンはIEnumerator型を戻り値として持ち、コルーチン内でyield returnステートメントを使用して非同期処理を表現します。
  実際の結果を返すのは難しいため、通常はコルーチン自体が状態を追跡する目的に使用されます。

 <UniTask>
   
  UniTaskはUniTask型を戻り値として持ち、非同期処理が完了した結果を持つことができます。これにより、非同期処理の結果を簡単に取得できます。


2.待機前提の違い

 <コルーチン>

  コルーチンは明示的なyield returnステートメントを使用して待機を表現し、コードの特定のポイントで処理が一時停止されます。
  コルーチン内の処理は通常待機ステートメントの周りに組み込まれます。

 <UniTask>

   UniTaskでは、非同期メソッドをawaitすることによって待機を表現します。
   待機は非同期処理の一部として自然な形で組み込まれ、コードの直列化が容易です。


3.例外処理の違い

 <コルーチン>

   コルーチン内で例外がスローされると、Unityエディタ内でエラーログが表示されますが、アプリケーション全体には波及しません。


 <UniTask>

   UniTaskはtry...catchブロックを使用して例外処理を行うことができ、例外をキャッチして適切な処理を実行できます。
   UniTaskはアプリケーション全体の例外ハンドリングをサポートしやすい環境にあります。


4.非同期処理の性能

 UniTaskは内部的に高度な非同期ライブラリを使用し、コルーチンよりも高性能で効率的です。
 UniTaskはより少ないオーバーヘッドを持ち、メモリ効率が高いため、多くの場面でコルーチンよりも好ましい選択肢となります。


2.エラーハンドリング


 エラーハンドリングについて、比較しながら学習します。


1.コルーチンの場合



using System.Collections;
using UnityEngine;

public class CoroutineErrorHandling : MonoBehaviour
{
    private void Start()
    {
        StartCoroutine(MyCoroutine());
    }

    private IEnumerator MyCoroutine()
    {
        Debug.Log("Coroutine Started");
        yield return new WaitForSeconds(2.0f);
        Debug.LogError("Coroutine Error");
    }
}


2.UniTaskの場合



using Cysharp.Threading.Tasks;
using UnityEngine;

public class UniTaskErrorHandling : MonoBehaviour
{
    private async void Start()
    {
        Debug.Log("UniTask Started");
        await UniTask.Delay(TimeSpan.FromSeconds(2));
        Debug.LogError("UniTask Error");
    }
}


3. キャンセル可能なタスク


 UniTaskはコルーチンよりも簡単にキャンセルできますが、コルーチンではキャンセルが難しいです。



1.コルーチンの場合



using System.Collections;
using UnityEngine;

public class CoroutineCancellationExample : MonoBehaviour
{
    private Coroutine myCoroutine;

    private void Start()
    {
        myCoroutine = StartCoroutine(MyCoroutine());
        // 2秒後にコルーチンをキャンセル
        StartCoroutine(CancelCoroutineAfterDelay(2.0f));
    }

    private IEnumerator MyCoroutine()
    {
        Debug.Log("Coroutine Started");
        while (true)
        {
            yield return null;
        }
    }

    private IEnumerator CancelCoroutineAfterDelay(float delay)
    {
        yield return new WaitForSeconds(delay);
        StopCoroutine(myCoroutine); // コルーチンをキャンセル
        Debug.Log("Coroutine Canceled");
    }
}


2.UniTaskの場合



using Cysharp.Threading.Tasks;
using UnityEngine;

public class UniTaskCancellationExample : MonoBehaviour
{
    private async void Start()
    {
        // UniTaskを使用して非同期タスクを開始
        var task = MyUniTask();
        
        // 2秒後にタスクをキャンセル
        await UniTask.Delay(2000);
        task.Cancel();
        Debug.Log("UniTask Canceled");
    }

    private async UniTask MyUniTask()
    {
        Debug.Log("UniTask Started");
        while (true)
        {
            await UniTask.Yield();
        }
    }
}

 このサンプルコードでは、コルーチンとUniTaskのキャンセル可能なタスクの違いを示しています。

 コルーチンの場合、キャンセルを実装するのに追加のロジックが必要で、StopCoroutineを使用してコルーチンをキャンセルします。

 一方、UniTaskではawaitの代わりにtask.Cancel()を使用して簡単にタスクをキャンセルできます。

 そういった点においても、UniTaskはキャンセル可能なタスクを管理しやすく、コードをよりシンプルに保ちます


4.複数の非同期処理の待機


 ここでもそれぞれの書き方を比較してみましょう。
 

1.コルーチンの場合


using System.Collections;
using UnityEngine;

public class CoroutineMultipleTasks : MonoBehaviour
{
    private void Start()
    {
        StartCoroutine(DoMultipleTasks());
    }

    private IEnumerator DoMultipleTasks()
    {
        Debug.Log("Coroutine Started");
        yield return StartCoroutine(Task1());
        yield return StartCoroutine(Task2());
        Debug.Log("All Coroutine Tasks Finished");
    }

    private IEnumerator Task1()
    {
        yield return new WaitForSeconds(2.0f);
        Debug.Log("Coroutine Task 1 Finished");
    }

    private IEnumerator Task2()
    {
        yield return new WaitForSeconds(1.0f);
        Debug.Log("Coroutine Task 2 Finished");
    }
}


2.UniTaskの場合


using Cysharp.Threading.Tasks;
using UnityEngine;

public class UniTaskMultipleTasks : MonoBehaviour
{
    private async void Start()
    {
        Debug.Log("UniTask Started");
        await Task1().ToUniTask();
        await Task2().ToUniTask();
        Debug.Log("All UniTask Tasks Finished");
    }

    private async UniTaskVoid Task1()
    {
        await UniTask.Delay(TimeSpan.FromSeconds(2));
        Debug.Log("UniTask Task 1 Finished");
    }

    private async UniTaskVoid Task2()
    {
        await UniTask.Delay(TimeSpan.FromSeconds(1));
        Debug.Log("UniTask Task 2 Finished");
    }
}

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu



技術/知識(実装例)

2Dおはじきゲーム(発展編)

2D強制横スクロールアクション(発展編)

3Dダイビングアクション(発展編)

2Dタップシューティング(拡張編)

レースゲーム(抜粋)

2D放置ゲーム(発展編)

3Dレールガンシューティング(応用編)

3D脱出ゲーム(抜粋)

2Dリアルタイムストラテジー

2Dトップビューアドベンチャー(宴アセット使用)

3Dタップアクション(NavMeshAgent 使用)

2Dトップビューアクション(カエルの為に〜、ボコスカウォーズ風)

VideoPlayer イベント連動の実装例

VideoPlayer リスト内からムービー再生の実装例(発展)

AR 画像付きオブジェクト生成の実装例

AR リスト内から生成の実装例(発展)

private



このサイト内の作品はユニティちゃんライセンス条項の元に提供されています。

管理人/副管理人のみ編集できます