Unity - coroutines 协程揭秘
下面给大家揭秘下Unity coroutines 协同系统,主要是帮助大家去理解UNity协同系统并让大家可以更有效地使用它。UNity协同程序可能似乎有点奇怪,很少有人知道他们是如何工作的,所以建议那些不了解UNity协同程序的一定要看看。
了解IEnumerator
你能猜到,协同工作与 IEnumerator接口和 CLR 枚举实现有关,所以我们首先应该明白这些东西是如何工作。最初, IEnumerator和IEnumerable应该处理的集合的Item,如lists or arrays。想象一下,一个字符串,也可以是一个字符数组。循环访问集合的常用方法是使用foreach语句:
这整洁的声明和IEnumerable接口,只知道如何提供IEnumerator一起工作。enumerator 告诉小 “story” 的如何遍历当前集合 (它可以提供当前元素,并知道如何移动到下一个)。总体来看,它看上去有点像这样:
这么说,这是foreach语句, 它在编译时:
IEnumerator也实现IDisposable,所以它是完全合法using语句内使用它。
迭代器 Iterators
这是关键的话题。我们实际上几乎就是协同程序本身。在我们的示例中,foreach 语句是枚举的enumeration的一个消费者,而迭代器是enumeration的生产者。看看代码:
看看线 # 12。yield语句, IEnumerable返回类型,以及是什么使得它都如此特别。return语句给你一个 该方法返回yield return 集合的下一个元素,你问此方法以yield 从enumerator 的值。每次遇到了yield ,控制返回到调用方,和它返回到 calee,在下一次它捡起并继续。编译器实际上将这种方法 (Fibs(...)) 转换成拼接这个yield return的逻辑, 纳入MoveNext方法和Current属性的私有类。当调用此方法时,你只是 实例化编译器编写的类 和无代码实际运行! 只有当你开始枚举此“on-the-fly”集合时,将运行您的代码!
迭代器可以有一个或多个yield
语句并且应该返回以下的接口来绕过编译器错误:
System.Collections.IEnumerable
System.Collections.Generic.IEnumerable<T>
System.Collections.IEnumerator
System.Collections.Generic.IEnumerator<T>
也是yield break
的语句,它允许终止迭代,所以没有更多的元素从enumerator返回。
回到协同程序
让我们看看此enumerator 逻辑如何转化为Unity协同程序。你可能已经注意到,协同程序通常yield return不同时间跨度或null, 如果代码需要继续在下一帧。这是因为Unity需要这些返回的值,以知道何时调用MoveNext()方法! 当你写你协同程序。例如以这段代码:
正如你所看到的还有一个yield return 语句返回传递的 WaitForSeconds对象,用于延迟。“tick” 消息将立即写入控制台,和在那之后的每一秒。尝试移动Debug.Log(..)调用后yield return语句,看看会发生什么。
让我们看看在调用TestCoroutine方法时,会发生什么。
似乎没有什么发生,但我们实际上在堆中创建enumerator 对象。你也可以做出这样的事情:
但无论如何它们确实很酷。
时刻牢记
- 创建协同是创建一个迭代器,通过虚构的collection of items 的过程。
- 迭代器返回值用于确定MoveNext方法到下一次调用的时间。
- 每次StartCoroutine被调用, 协同程序将分配在堆中分配一个 enumerator 对象。
希望这将帮助你更有效。你也可以打动你的同事与自定义协同执行!
最后,贴上一个自定义实现的协程程序:http://wiki.unity3d.com/index.php?title=CoroutineScheduler