简体   繁体   English

理解协同程序的执行

[英]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. 我在Unity工作,但这只是一个C#问题所以我希望这是发布这个问题的正确部分。 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,FixedUpdate和Coroutine添加到我的“何时运行”列表中而变得更加复杂? 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. 至于Coroutine,我基本上理解它是一种功能,可以让我更准确地控制时间。 It's the only way I know I can do "yield return new WaitForSeconds(i);" 这是我知道我能做的唯一方法“收益返回新的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? 例如,如果我从更新调用协程(每帧运行一次)并且协程有一个waitforseconds(10),那么将暂停执行所有脚本? 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. 您需要知道的第一件事是使用yield关键字并返回IEnumerable的函数将转换为迭代器。 It's syntactic sugar for writing a class that implements IEnumerator . 它是编写实现IEnumerator的类的语法糖。

They're usually used in conjunction with foreach loops: 它们通常与foreach循环一起使用:

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> . 这里发生的是GetFruits返回一个实现IEnumerator<string>的生成器对象。 Its MoveNext method runs part of the original GetFruits code each time it is called. 它的MoveNext方法每次MoveNext都会运行原始GetFruits代码的一部分。 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. 每次调用执行代码到下一个yield的语句,并使用的“返回值” yield设定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: foreach循环导致代码调用MoveNext并将Current存储到循环变量中,这使得迭代更具可读性,如下所示:

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. 您可以存储对生成器的引用并调用其MoveNext方法,例如,每秒一次。 Or whenever a user presses a button. 或者每当用户按下按钮时。 Or you could use the Current value to determine when MoveNext should be called again. 或者您可以使用Current值来确定何时应再次MoveNext

And that's exactly what Unity is doing. 这正是Unity正在做的事情。 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. 当协WaitForSeconds对象时,Unity会更新该协程的等待时间,并且在等待时间结束之前不会再次调用该协程的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. 除非协程仍处于“等待”状态,否则Unity会在每个“更新周期”上调用游戏对象上的Update和协同程序上的MoveNext A coroutine that's waiting is simply being skipped - it doesn't block any other code. 正在等待的协程只是被跳过 - 它不会阻止任何其他代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM