问题描述
我感到困惑和好奇如何(在Unity3D也许是其他地方)的工作。协同程序是一个新的线程? Unity的他们说:
And they have C# examples here:
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);
}
}
I have many questions about this example:
In the example above, which line is the coroutine? Is
WaitAndPrint()
a coroutine? IsWaitForSeconds()
a coroutine?In this line:
yield return new WaitForSeconds(waitTime);
, why bothyield
andreturn
are present? I read in Unity documentation that "The yield statement is a special kind of return, that ensures that the function will continue from the line after the yield statement next time it is called." Ifyield
is a specialreturn
, what isreturn
doing here?Why do we have to return an
IEnumerator
?Does
StartCoroutine
start a new thread?How many times has
WaitAndPrint()
been called in the above example? Didyield return new WaitForSeconds(waitTime);
really returned? If yes then I guessWaitAndPrint()
was called twice in the above code. And I guessStartCoroutine()
was callingWaitAndPrint()
multiple times. However, I saw another Unity documentation that says: "The execution of a coroutine can be paused at any point using the yield statement. The yield return value specifies when the coroutine is resumed." These words make me feel thatWaitAndPrint()
actually has not returned; it was merely paused; it was waiting forWaitForSeconds()
to return. If this is the case, then in the above codeWaitAndPrint()
was called only once, andStartCoroutine
was just responsible for starting the function, not calling it multiple times.
Coroutines are an extremely powerful technique used to emulate the kinds of features supported by the async/await in .net4.5, but in earlier versions ( c# >= v2.0 ) .
Microsoft CCR (take a read) also employs (employed?) this approach.
Let's get one thing out of the way. yield
alone is not valid and is always followed by either return
or break
.
Think about a standard IEnumerator (that doesn't yield flow control messages).
IEnumerator YieldMeSomeStuff()
{
yield "hello";
Console.WriteLine("foo!");
yield "world";
}
Now:
IEnumerator e = YieldMeSomeStuff();
while(e.MoveNext())
{
Console.WriteLine(e.Current);
}
What's the output?
hello foo! world
Notice how, the second time we called MoveNext
, before the Enumerator yielded "world" some code ran within the Enumerator. What this means is that in the Enumerator, we can write code that executes until it hits a yield return
statement, then simply pauses until someone calls MoveNext
(handily with all state/variables neatly captured, so we can pick up where we left off). After a MoveNext
call, the next bit of code after the yield return
statement can run until another yield return
is reached. So we can now control the execution of the code between the yield return
statements with the MoveNext
call to the Enumerator.
Now, say instead of yielding strings, our Enumerator were to yield a message that says to the caller of MoveNext
, "please hang around for x (waitTime) seconds before you call MoveNext
again". The caller is written to "understand" a variety of messages. These messages will always be along the lines of "please wait for such and such to happen before calling MoveNext
again".
Now we have a powerful means of pausing and restarting code that requires other conditions to be met before it can proceed, without having to write that functionality into another method, like doing async stuff without coroutines. Without coroutines, you're forces to pass around a horrible async state object that you would need to manually assemble to capture state between the end of one method and the starting of another after some async stuff). Coroutines eliminate this because scope is preserved (by compiler magic), so your local variables persist over long lived async stuff.
StartCoroutine
simply starts the whole process. It calls MoveNext
on the Enumerator... some code runs in the Enumerator... The enumerator yields a control message, which informs the code in StartCoroutine
when to call MoveNext
again. This need not happen in a new Thread, but can be handy in multithreaded scenarios because we can call MoveNext
from different threads and control where the work is done.
这篇关于协程是在Unity3D一个新线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!