コルーチン (Unity3Dやおそらく他の場所で)がどのように機能するかについて、私は混乱していて興味があります。コルーチンは新しいスレッドですか? Unityの ドキュメント 彼らは言った:
コルーチンは、指定されたYieldInstructionが終了するまでその実行(yield)を一時停止できる関数です。
そして、C#の例があります ここ :
_using UnityEngine;
using System.Collections;
public class example : MonoBehaviour {
void Start() {
print("Starting " + Time.time);
StartCoroutine(WaitAndPrint(2.0F));
print("Before WaitAndPrint Finishes " + Time.time);
}
IEnumerator WaitAndPrint(float waitTime) {
yield return new WaitForSeconds(waitTime);
print("WaitAndPrint " + Time.time);
}
}
_
この例について多くの質問があります。
上記の例では、コルーチンはどの行ですか? WaitAndPrint()
はコルーチンですか? WaitForSeconds()
はコルーチンですか?
この行:yield return new WaitForSeconds(waitTime);
、なぜyield
とreturn
の両方が存在するのですか? nityのドキュメント を読みました。「yieldステートメントは特別な種類の戻り値であり、次に呼び出されたときに関数がyieldステートメントの後の行から継続することを保証します。」 yield
が特別なreturn
である場合、ここでreturn
は何をしていますか?
なぜIEnumerator
を返さなければならないのですか?
StartCoroutine
は新しいスレッドを開始しますか?
上記の例でWaitAndPrint()
は何回呼び出されましたか? yield return new WaitForSeconds(waitTime);
は本当に返されましたか?はいの場合、上記のコードでWaitAndPrint()
が2回呼び出されたと思います。そして、StartCoroutine()
がWaitAndPrint()
を複数回呼び出していたと思います。ただし、 別のUnityドキュメント は、「コルーチンの実行は、yieldステートメントを使用していつでも一時停止できます。yieldの戻り値は、コルーチンがいつ再開されるかを指定します。」と表示されます。これらの言葉は、WaitAndPrint()
が実際には戻っていないように感じさせます。一時停止しただけです。 WaitForSeconds()
が戻るのを待っていました。この場合、上記のコードでは、WaitAndPrint()
は1回だけ呼び出され、StartCoroutine
は関数の開始のみを担当し、複数回は呼び出されませんでした。
コルーチンは、.net4.5のasync/awaitでサポートされている機能の種類をエミュレートするために使用される非常に強力な手法ですが、以前のバージョン(c#> = v2.0)では使用されていました。
Microsoft CCR (読んでください)もこのアプローチを採用しています(採用されていますか?)。
邪魔にならないようにしましょう。 yield
だけでは無効であり、その後に常にreturn
またはbreak
が続きます。
標準のIEnumerator(フロー制御メッセージを生成しない)について考えてみてください。
IEnumerator YieldMeSomeStuff()
{
yield "hello";
Console.WriteLine("foo!");
yield "world";
}
今:
IEnumerator e = YieldMeSomeStuff();
while(e.MoveNext())
{
Console.WriteLine(e.Current);
}
出力は何ですか?
こんにちは foo! world
列挙子が「ワールド」を生成する前に、2回目にMoveNext
を呼び出したときに、列挙子内で実行されたコードに注目してください。つまり、列挙子では、yield return
ステートメントに到達するまで実行し、誰かがMoveNext
を呼び出すまで一時停止するコードを記述できます(すべての状態/変数が適切にキャプチャされているため、中断したところから再開できます)。 MoveNext
呼び出しの後、yield return
ステートメントの後のコードの次のビットは、別のyield return
に到達するまで実行できます。これで、列挙子へのMoveNext
呼び出しを使用して、yield return
ステートメント間のコードの実行を制御できます。
さて、文字列を生成する代わりに、列挙子がMoveNext
の呼び出し元にメッセージを生成するとします。 "呼び出す前にx(waitTime)秒間しばらくお待ちください。 MoveNext
再び "。発信者は、さまざまなメッセージを「理解」するように書かれています。これらのメッセージは常に "MoveNext
を再度呼び出す前にそのようなことが起こるのを待ってください"の行に沿っています。
これで、コルーチンなしで非同期処理を実行するなど、別のメソッドにその機能を書き込むことなく、続行する前に他の条件が満たされる必要があるコードを一時停止および再起動する強力な手段ができました。コルーチンがないと、あるメソッドの終了から別のメソッドの開始までの間に状態をキャプチャするために手動でアセンブルする必要がある恐ろしい非同期状態オブジェクトを強制的に渡す必要があります)。コルーチンはスコープが(コンパイラの魔法によって)保持されるため、これを排除します。そのため、ローカル変数は長期間有効な非同期のものにわたって存続します。
StartCoroutine
は単にプロセス全体を開始します。列挙子でMoveNext
を呼び出します...一部のコードは列挙子で実行されます...列挙子は制御メッセージを生成し、StartCoroutine
のコードにいつMoveNext
を呼び出すかを通知します再び。これは新しいスレッドで発生する必要はありませんが、さまざまなスレッドからMoveNext
を呼び出して作業の実行場所を制御できるため、マルチスレッドのシナリオで便利です。