Unity中coroutine问题的示例分析
这篇文章主要介绍了Unity中coroutine问题的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
1、从表面看协程的执行顺序
一个最简单的协程函数:
IEnumeratorTest(){yieldreturnnewWaitForSeconds(1);Debug.Log("End");}//在其它地方StartCoroutine(Test());
作用:当你在其它地方执行了StartCoroutine(Test());之后,1秒之后打印“End”。
在开启协程之后,Test何时被调用?答案其实是每帧都要调用一次。(对迭代器函数来说,意思是每帧继续执行一次)。
如果每帧都继续,那么Test为什么最终在一秒后继续执行呢?答案在WaitForSeconds里面。
流程是这样的:
1、在StartCoroutine(Test())里,Test第一次被执行,yield中止并返回一个“WaitForSeconds(1)”对象。
2、执行StartCoroutine时,Unity内部注册这个Test函数。因为之后每帧都要调用,Unity内部先记下来。
3、这里,返回的WaitForSeconds(1)其实是一个小花招,它的设计思路是:
如果(Time.time小于之前说好的时间){返回:没结束;}返回:结束了,继续。//这里用伪码表示,想知道原理可以看后面的Unity官方说明文档
4、记住:协程函数每帧都要调用一次。于是Unity引擎层在这一秒,每帧都调用Test函数,重复了几十次,每次都被WaitForSeconds挡住,无法往下执行。
5、直到某一次调用,时隔1秒后了,WaitForSeconds终于放行了,Test才有机会继续执行,打印“End”。
这就是以WaitForSeconds为例解释的,协程的执行流程,以及等待1秒的原理。
2、解释yield return www;
现在可以回到题主问题了,其实yield return www 和 yield return new WaitForSeconds(1)是完全一样的道理,WWW的设计是:
如果(网络请求还在进行中){返回:没结束;}返回:结束了
同样的方式,如果网络请求没完成,那么你的协程函数就会被www阻拦住。这样就巧妙实现了一种异步机制,整个游戏不会因为www而卡住。
3、Unity如何做到这一点的?
eldereal 的回答很详细,其实C#根本就不支持真正的协程,而只支持迭代器。
由于游戏引擎的特殊性(每帧更新),Unity很巧妙的把迭代器改装成了一个似乎能并行执行的东西,也确实很好用。
别忘了,WWW和WaitForSeconds都是Unity提供的类,并不是C#原本就支持的。如果你很好奇,想扩展出自己的类似WWW的类,参考官方文档自定义Yield对象:
CustomYieldInstruction
https://docs.unity3d.com/ScriptReference/CustomYieldInstruction.html
由于Unity的这种“伪”协程属于自己制定的方案,未来引擎更新时候甚至会修改设计,所以理解调用顺序和大致原理更重要,不要拘泥于代码本身。
4、其它说明
Unity的Coroutine机制设计的很好,就是这个名字起的太有问题了,无论英文的Coroutine和中文的协程,都很不合适。
有一定golang、python gevent、skynet开发经验的人(主要是服务器端的),都对协程有较好的理解,而Unity的协程与真正的协程差异太大了。起同样的名字带来很大的误导作用,交流也很困难。
一句话解释Unity协程:其实Unity的Coroutine在我看来,更像是“注册一个 每帧都调用的函数”,只不过这个函数支持yield中止,仅此而已。
感谢你能够认真阅读完这篇文章,希望小编分享的“Unity中coroutine问题的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!