很多unity关于协程的教程都集中在讲协程的表象,即:在某某情况下协程怎么实现,有什么作用。 但了解协程的具体实现方法必然可以帮助自己更好的使用这个工具。
协程的作用: 需要跨越多个帧的“动作”有很多实现的方式,协程提供了一种比较简洁的方式。 即startcorountine(), 在一帧中开始一个“动作“,然后接下来几帧中依然会产生效果。这和另外起一个线程有相似之处。但在游戏中多线程的应用有局限性。原因我猜想如下:游戏需要对每一帧的信息进行计算处理,虽然协程看起来像是把计算放到另一个线程,但实际上引擎依旧需要每一帧都按顺序计算相关信息。 也就是说,把信息保存下来,每一帧都用迭代器去访问需要的信息就是自然的想法了,并没有用多线程。而这种方式相比于多线程会出现的诸多同步问题,优势不言而喻。
所以协程就是一个迭代器的应用场景。
IEnumerator
是迭代器。C#1中要继承一个迭代器比较复杂,至少需要实现构造函数,Movenext(),reset(),current属性。 C#2中,可以简化上述步骤,即Movenext(),reset(),current属性已经帮你实现好了,但相应的,你自己就不知道这三个东西的调用时机和实现方式了。简化了的实现方法需要借助yield实现。可以参考这篇博客,讲得很清楚:https://www.cnblogs.com/w-wfy/p/7418459.html。
yield
用yield return value, 那么不管value的类型是什么,最后的返回值是 一个类的实例,这个类是编译器帮忙实现了IEnumerator接口的一个类。这个类的形式如下(由反编译而来) : 实现了Movenext(),reset(),current等方法属性。 值得注意的是movenext()的实现方法,直接在一个switch保存了每种状态应该干的事情。简单粗暴。
- private sealed class <Power>d__0 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable
- {
- private int <>1__state;
- private int <>2__current;
- public int <>3__exponent;
- public int <>3__number;
- private int <>l__initialThreadId;
- public int <result>5__1;
- public int exponent;
- public int number;
- [DebuggerHidden]