こんにちは、Unityエンジニアのオオバです。
みなさまasync/await
を使っていますでしょうか?Unityで非同期処理を書くなら UniTask一択 です。
正直もうコルーチンの記述には戻りたくないです。それだけコルーチンと比べて UniTaskは書きやすい んですよね。
使ってみるとわかるんですが、 UniTaskはコルーチンとまったく別物です。
UniTaskを始めてみる、またはコルーチンをUniTaskに置き換えるにしても、特性や違いを理解なしに使うと思わぬトラブルが発生 します。
本記事では コルーチンとUniTask(async/await)の違い について、初心者向けに解説していきます。
ぜひともUniTaskをマスターして非同期処理を気持ちよく書いてもらいたいです。
まだUniTaskを使ってない方はこちらの導入記事をどうぞ。
👉DOTweenの教科書を読んでUnityアニメーションをプログラミングしてみよう!
コルーチンとUnityタスクの違い3点
コルーチンとUniTaskは大きく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はUnity界ではモダンな技術。さまざまなプロダクトで採用されています。
コルーチンと比べると大幅にコード量を減らせますし、見通しのよいプログラミングになります。
今後新規でゲームを作る際にはUniTask一択という感じです。
UniTaskとコルーチンの違いのまとめ
記事の内容を簡単にまとめます。
①戻り値の取得が可能なためUniTaskはコードがスッキリする
②UniTaskはMonoBehaviourから独立した存在
③GameObjectのOFFやDestroyでUniTaskは止まらないので慣れが必要
こんな感じです。
コルーチンとの違い、特性をしっかり理解しておかないとトラブルに巻き込まれます。
「UniTaskにしたらエラーが大量にでる」 みたいな。 GameObjectのライフサイクルから独立している点 に最初は戸惑うかも知れません。
何度も書いているとすぐに慣れますし、 書き味の良さ を感じられると思います。
いきなり仕事で使うにはリスクがあるかも知れないので、まずは個人プロダクトから導入してみてはいかがでしょうか。
また本記事では触れられていない便利機能がUniTaskには山程あります。
それらを触りつつ、コルーチンとの違いを体で感じつつ技術力を上げていくとよいのかなと思う次第です。
この記事が気に入ったらフォローしよう
「Unity初心者大学」というUnity初心者向けのYouTube始めました!!
ぜひチャンネル登録をお願いします!
最後まで読んでいただきありがとうございました!
すばらしいUniTaskライフをお過ごしください。
- Unity2020.3.19f1
- UniTask v2.2.5