Understanding The Execution of Coroutines
I'm working in Unity, but this is really just a C# question so I hope this is the right section to post this. Anyways, I still have trouble visualizing the execution of scripts in my head, especially when there are more than one running and they all have different functions.
It's gotten more complicated recently as I've added Update, FixedUpdate, and Coroutine to my list of "When's this running"? Update and Fixed Update I get the gist.
As for Coroutine, I basically understand it's a type of function that gives me a more precise control of timing. It's the only way I know I can do "yield return new WaitForSeconds(i);"
My question is more about their execution order. For example if I call a coroutine from update(which runs once per frame) and that coroutine has a waitforseconds(10), then will pause execution of all script? Is there like one central clock running everything? Will Update not run again until the wait is up? What if I've got another script with an update function containing a different coroutine waiting as well and both run at the same time?
Maybe I'm being to vague. Hard to explain. I've read a couple of pieces of information online about coroutine, but nothing that really explains it in a way I can visualize it.
The first thing you need to know is that functions that use the yield
keyword and return an IEnumerable
are turned into iterators. It's syntactic sugar for writing a class that implements IEnumerator
.
They're usually used in conjunction with foreach
loops:
IEnumerable<string> GetFruits()
{
yield return "Apple";
yield return "Pear";
}
foreach (string fruit in GetFruits())
Console.WriteLine(fruit);
What happens here is that GetFruits
returns a generator object that implements IEnumerator<string>
. Its MoveNext
method runs part of the original GetFruits
code each time it is called. Each call executes code up to the next yield
statement, and uses the 'return value' of that yield
to set the Current
property of the generator.
The foreach
loop results in code that calls MoveNext
and that stores Current
into the loop variable, which makes iteration much more readable, something like the following:
IEnumerator<string> fruitsGenerator = GetFruits().GetEnumerator();
while (fruitsGenerator.MoveNext())
{
string fruit = fruitsGenerator.Current;
Console.WriteLine(fruit);
}
But you're not limited to using iterators in loops. You can store a reference to a generator and call its MoveNext
method, say, once per second. Or whenever a user presses a button. Or you could use the Current
value to determine when MoveNext
should be called again.
And that's exactly what Unity is doing. A coroutine is essentially a generator object (with some extra information, such as how much time is left until it should be called again). When a coroutine yields a WaitForSeconds
object, Unity updates the waiting-time of that coroutine and will not call that coroutine's MoveNext
method again until the waiting time is over.
Each 'update cycle', Unity calls Update
on your game-objects and MoveNext
on your coroutines, unless a coroutine is still in a 'waiting' state. A coroutine that's waiting is simply being skipped - it doesn't block any other code.
上一篇: 如何理解这个Unity协程?
下一篇: 了解协程的执行