Unityのコルーチンで、yield return
で待つ方法と MoveNext() & Current
で待つ2つのパターンがある。
どう違うのかを検証してみた。
先に軽い結論
どうやら完了時までの最低経過フレーム数で差が出る
検証してみる
実際に両方のテストコードを書いて実行してみた
前提知識
Time.frameCount
- 実行してから現時点まで経過フレーム数を取得できる。
- コルーチンを呼ぶ前と後でこいつをログで表示して経過フレーム数を測定する。
検証コード
.cs
using System.Collections;
using UnityEngine;
// コルーチン実行テスト
public class TestMain : MonoBehaviour {
void Start ()
{
// yield return の実行テスト
//StartCoroutine(TaskForYieldReturn()); // --- (1)
// .MoveNext の実行テスト
//StartCoroutine(TaskForMoveNext()); // --- (2)
}
// 直接yield return の実行テスト
private IEnumerator TaskForYieldReturn()
{
Debug.Log($"START : [ {Time.frameCount} ]");
yield return StartCoroutine( SubTask() );
Debug.Log($"END : [ {Time.frameCount} ]");
}
// .MoveNext の実行テスト
private IEnumerator TaskForMoveNext()
{
Debug.Log($"START : [ {Time.frameCount} ]");
var e = SubTask();
while(e.MoveNext()) { yield return e.Current; }
Debug.Log($"END : [ {Time.frameCount} ]");
}
// 遅延処理がないコルーチン
private IEnumerator SubTask()
{
Debug.Log($"SubTask : [ {Time.frameCount} ] ");
yield break;
}
}
実行手順
- 上のプログラムを適当な空の
GameObject
にAddComponent
する - 直接
yield return
のテストをする場合:Start関数内の---(1)
の行コメントアウトを外して実行する -
.MoveNext
のテストをする場合:Start関数内の---(2)
の行コメントアウトを外して実行する
それぞれの実行結果
直接yield return
の実行結果
STARTログからENDログの表示まで、1フレーム経過している
.MoveNext
の実行結果
STARTログからENDログの表示まで、同フレームで完了している
結論
完了タイミングが最低1フレームを待つかどうかの違い。
IEnumeratorで即座に完了するものがある場合は、.MoveNext
のほうを使うと良い。
使い道としては、Command
パターンなど、親クラスに virutal IEnumerator Execute()
のようなコルーチンを継承先で override
して、待たせる処理をする/しないの違いをさせる場合など。
余談
ちなみに、
yield return SubTask();
の部分は、
yield return StartCoroutine( SubTask() );
と書き直しても同じ結果だった