Unity协程的原理和协程与线程与进程的区别
这篇文章适合有一定协程使用基础的开发者看,不了解协程是什么概念的可以先看看官网
Unity协程的原理
说起协程的原理,就要谈起c#的迭代器功能:
简单来说,类继承了IEnumerable接口并且实现了GetEnumerator()方法就可以使用foreach去遍历类,遍历输出的结果是根据GetEnumerator()的返回值IEnumerator确定的。这种写法有些繁琐,c#就推出了yield关键字来对其进行简化。
简化成这样了,代码如下所示
IEnumerator TestCoroutine()
{
Debug.Log("1111");
yield return null; //返回内容为null
Debug.Log("2222");
yield return 1; //返回内容为1
Debug.Log("3333");
yield return "sss"; //返回内容为"sss"
Debug.Log("4444");
yield break; //跳出,类似普通函数中的return语句
yield return 999; //由于break语句,该内容无法返回
}
void Start()
{
IEnumerator e = TestCoroutine();
while (e.MoveNext())
{
Debug.Log(e.Current); //依次输出枚举接口返回的值
}
}
上面的代码基本上用到的就是纯粹的c#的迭代器功能,
IEnumerator e = TestCoroutine();
执行的时候其实方法并没有执行,只是单纯获得一个IEnumerator类型的返回值e
在接下来第一次调用
e.MoveNext()
这个方法的时候,TestCoroutine就会执行完yield return null;
然后会停止,e.MoveNext()返回true,e.Current的值是null
第二次调用的时候,TestCoroutine就会执行完yield return 1;
然后会停止,e.MoveNext()返回true,e.Current的值是1
第三次调用的时候,TestCoroutine就会执行完yield return "sss";
然后会停止,e.MoveNext()返回true,e.Current的值是"sss"
第四次调用的时候,TestCoroutine就会执行完yield break;
然后会停止,e.MoveNext()返回false,e.Current的值是"sss",因为返回的是false,所以while循环会退出。
这里对其结果进行解释说明下,MoveNext执行的时候,方法就会挨个执行yield,执行一次然后停止,当yield 后面跟了return的时候,MoveNext的返回值就是true ,即使return的是null,如果yield 后面 没有跟 return,则MoveNext就会返回false,如果这时再继续执行MoveNext,则会报错。
这是c#的迭代器的运行过程,关于c#如何实现迭代器的可以参考微软的Iterators (C#)
Unity的协程是基于此实现的,在Unity中,协程的等待主要有三种,
- 等待固定时机如等待一次绘制帧,等待一次物理帧
- 等待开发者定义的实际时间,如等待两秒
- 等待另外一个协程方法执行结束
开发者自己实现Unity的协程方案如下:
对于第一种,实现原理是在每次Update或者FixedUpdate调用的时候执行一次MoveNext()方法,只要返回值不为false,下一帧就可以继续执行
对于第二种,实现原理是在每次Update或者FixedUpdate调用的时候通过+= Time.deltaTime
或者 += Time.FixedDeltaTIme
进行一次时间叠加计算,当倒计时达到的时候就执行一次MoveNext方法,然后如果MoveNext返回true就重置倒计时
对于第三中,实现原理是先启动需要等待的协程,在每次其执行MoveNext的时候判断一次MoveNext的返回值,返回值为false的时候,就启动正在等待的协程。
参考博客:Unity 协程原理探究与实现
协程与线程与进程的区别
协程和线程和进程的区别可以用上图来表示。
上图中,进程里面可以有两个或者多个线程,Unity工作最主要的是主线程,其余的线程主要是用来渲染,而一般在主线程里面开辟的多个协程都是在主线程里面的。
一个应用程序一般对应一个进程,一个进程一般有一个主线程,还有若干个辅助线程,线程之间是平行运行的,在线程里面可以开启协程,让程序在特定的时间内运行。
图中一个进程里面两个线程真的会同时运行,就好像两个人同时在工作一样,而在Unity中,一个线程里面开启多个协程,假设每个协程都是一帧执行一次的,是简单的把一帧的时间因为多个协程的原因延长了,协程并不会真正的并行运行,只是延长的时间很短,这样每一帧就执行了多个协程,看起来就好像这些协程并行运行了一样。
进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。
线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(这里指标准线程)。
协程和线程一样共享堆,不共享栈,协程由开发者在协程的代码里显示调度。
协程和线程的区别是:协程避免了无意义的调度,死锁等问题隐患,由此可以提高性能和安全性,使用起来也比线程更加方便。但程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。
参考链接: unity 进程和协程原理与线程的区别(转)
本文地址:https://blog.csdn.net/weixin_43149049/article/details/107304573