Unity中的coroutine是经过yield expression;来实现的。官方脚本中处处会看到这样的代码。html
疑问:python
yield是什么?web
Coroutine是什么?express
unity的coroutine程序执行流程怎么那么奇怪?编程
unity中的coroutine原理是什么,怎么实现的?服务器
使用unity的coroutine须要注意什么问题?框架
1、yield的在几种语言中的程序执行特性:函数
Lua中的yield是使得协同函数运行->挂起而且传递参数给resume。resume使得协同函数挂起->运行而且传递参数给协同函数。性能
C#中yield return/break是用于函数查询集合生成器里面的值(相似迭代)返回,并记录当前现场,下次查询时从上一次记录的yield现场处,继续往下执行,直到继续往下执行没有了,那么退出这段yield的逻辑。yield break会终止掉yield迭代逻辑并跳出。
YieldImplementation:
1).Caller callsfunction
2).Caller requestsitem 按需请求一个元素
3).Next itemreturned 返回请求的元素
4).Goto step #2this
Python中的yield expression, 有yield的函数就变成了一个生成器,调用该函数返回的是迭代器对象,用迭代器对象调用next方法(或者循环中会自动调用next方法),才开始执行函数,执行到yield expression处则中断,返回迭代器当前的值,并保留现场,下次调用next则从现场处开始执行,迭代完了就中止了。能够看出Python中的yield和C#中的yield是相似的,用于建立生成器,执行时中断返回迭代器值,并记录现场,下次从现场处继续执行。
Unity中的yield就是和C#,python中的相似,由于unity是基于.net框架的,且unity脚本开始是用Boo(Python的一个变种)写的。只是unity中多了coroutine特性类型,和StartCoroutine的coroutine管理类。StartCoroutine不是启动了一个新的线程,而是开启一个协同程序,默认unity全部代码都在一个线程中(http://answers.unity3d.com/questions/280597/new-thread-vs-startcoroutine.html)。
coroutine语言层面的原理:
在两年前,协程彷佛是一个很高级的东西,随后大多数语言或多或少都支持协程。我比较熟悉的有Python的gevent,Lua的coroutine,Go的goroutine。尤为是Lua和Go,语言自己就支持协程。协程也被叫作轻量级线程。通俗点讲就是定义一大堆任务,而后经过一个线程轮着对每一个任务都执行一下,协做运行。它的厉害之处在于每运行到一个任务的时候,它均可以从这个任务上一次中断的地方开始运行。在咱们通常的印象中,只有操做系统对线程进行调度的时候才会干这样的事情,进行各类进栈,保存状态。而协程,总共也只是运行在一个线程中,要是使用线程自己的系统栈,早就暴了。所以在这里,实现的时候是用内存来模拟栈的操做。具体实现,我想复杂度必定会不小。
咱们知道,线程比进程轻量级,所以产生一个线程消耗的资源比进程少,上下文切换也比进程节约。而协程比线程更加轻量级,上下文切换更是迅速。因而在服务器编程方面给人无限想象。尽管目前尚未出现一款主流的采用协程的web服务器。可是Go语言开发的web服务的性能已经崭露头角了。
2、Unity的Coroutine执行现象:
第一种方法:
voidStart() { print("Starting " +Time.time); StartCoroutine(WaitAndPrint(2)); print("Done " +Time.time); } IEnumerator WaitAndPrint(float waitTime) { yield return new WaitForSeconds(waitTime); print("WaitAndPrint " + Time.time); }
该段代码的执行顺序是12435
执行到4协程注册了事件,控制权交给外部线程;外部线程执行到3;事件发生,程序分段执行机制goto到协程处记录了堆栈信息执行5语句。
// Use this for initialization void Start() { StartCoroutine(IEnumeratorStart()); } // Update is called once per frame void Update() { } IEnumerator IEnumeratorStart() { print("Starting " + Time.time); yield return StartCoroutine(WaitAndPrint(2.0F)); print("Done " + Time.time); } IEnumerator WaitAndPrint(float waitTime) { yield return new WaitForSeconds(waitTime); print("WaitAndPrint " + Time.time); }
该段代码的执行顺序是12453
Why?这么奇怪的执行方式。
程序执行到4,执行yield return表达式注册事件交出控制权给外部,由于外部还要交出控制权也须要执行yield return后面的表达式语句所以会重入WaitAndPrint函数接着协程当前状态下一步执行因此执行到5,yield return 后面表达式语句执行完毕控制权彻底交出,以后才执行3,根本缘由是yield return 不能直接嵌套后面须要跟一个表达式(事件)。
5、Unity中使用Coroutine须要注意的问题:
1.使用的地方和不能使用的地方:
必须在MonoBehaviour或继承于MonoBehaviour的类中调用 yield coroutine。yield不能够在Update或者FixedUpdate里使用。
2.开启协程:
StartCoroutine(string methodName)和StartCoroutine(IEnumeratorroutine)均可以开启一个协程,
区别:
使用字符串做为参数时,开启协程时最多只能传递一个参数,而且性能消耗会更大一点; 而使用IEnumerator 做为参数则没有这个限制。
3.删除协程:
1).在Unity3D中,使用StopCoroutine(stringmethodName)来终止该MonoBehaviour指定方法名的一个协同程序,使用StopAllCoroutines()来终止全部该MonoBehaviour能够终止的协同程序。
包括StartCoroutine(IEnumerator routine)的。
2).还有一种方法能够终止协同程序,即将协同程序所在gameobject的active属性设置为false,当再次设置active为ture时,协同程序并不会再开启;
如是将协同程序所在脚本的enabled设置为false则不会生效。
4.js和C#中使用区别:
在C#中要使用 yield return而不是yield。
C#中yield(中断)语句必需要在IEnumerator类型里,C#方法的返回类型为IEnumerator,返回值如(eg:yield return new WaitForSeconds(2); 或者 yield returnnull);