理解协程的执行 [英] Understanding The Execution of Coroutines
问题描述
我在 Unity 工作,但这实际上只是一个 C# 问题,所以我希望这是发布此内容的正确部分.无论如何,我仍然无法在脑海中想象脚本的执行情况,尤其是当有多个运行并且它们都有不同的功能时.
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.
对于协程,我基本上理解它是一种函数,可以让我更精确地控制时间.这是我知道我能做到的唯一方法收益率返回新的 WaitForSeconds(i);"
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);"
我的问题更多是关于他们的执行顺序.例如,如果我从 update 调用协程(每帧运行一次)并且该协程有一个 waitforseconds(10),那么会暂停所有脚本的执行吗?有没有像一个中央时钟运行一切?在等待结束之前更新不会再次运行吗?如果我有另一个带有更新函数的脚本,其中包含一个等待的不同协程并且两者同时运行怎么办?
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.
推荐答案
您需要知道的第一件事是使用 yield
关键字并返回 IEnumerable
的函数变成了迭代器.它是编写实现 IEnumerator
的类的语法糖.
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
.
它们通常与 foreach
循环结合使用:
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);
这里发生的是 GetFruits
返回一个实现了 IEnumerator
的生成器对象.它的 MoveNext
方法每次被调用时都会运行原始 GetFruits
代码的一部分.每次调用都执行代码直到下一个 yield
语句,并使用该 yield
的返回值"来设置生成器的 Current
属性.
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.
foreach
循环导致代码调用 MoveNext
并将 Current
存储到循环变量中,这使得迭代更具可读性,某些东西像下面这样:
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);
}
但您不仅限于在循环中使用迭代器.您可以存储对生成器的引用并调用其 MoveNext
方法,例如,每秒一次.或者每当用户按下按钮时.或者您可以使用 Current
值来确定何时应该再次调用 MoveNext
.
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.
这正是 Unity 正在做的事情.协程本质上是一个生成器对象(带有一些额外的信息,例如距离应该被再次调用之前还剩多少时间).当协程产生一个 WaitForSeconds
对象时,Unity 会更新该协程的等待时间,并且在等待时间结束之前不会再次调用该协程的 MoveNext
方法.
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.
每个更新周期",Unity 会在您的游戏对象上调用 Update
并在您的协程上调用 MoveNext
,除非协程仍处于等待"状态.正在等待的协程只是被跳过 - 它不会阻塞任何其他代码.
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.
这篇关于理解协程的执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!