zoukankan      html  css  js  c++  java
  • 【Unity3D/C#】Unity3D中的Coroutine详解

    Unity中的coroutine是通过yield expression;来实现的。官方脚本中到处会看到这样的代码。

    疑问:

    yield是什么?

    Coroutine是什么?

    unity的coroutine程序执行流程怎么那么奇怪?

    unity中的coroutine原理是什么,怎么实现的?

    使用unity的coroutine需要注意什么问题?

    一、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 #2

        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服务的性能已经崭露头角了。

    二、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 不能直接嵌套后面需要跟一个表达式(事件)。

    五、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);

  • 相关阅读:
    图片体验(转载)
    addClass和css性能分析
    css选择器性能测试
    XHTML+CSS兼容性解决方案
    ASP.NET Club Web Site Starter Kit扩展之一
    CommunityServer从V1.1转换为V2.0的问题
    ASP.NET官方网站有中文版本了
    ASP.NET2.0登陆控件的使用(常见的三种方法)
    ASP.NET BLOGS Starter Kit(C#)准备发布
    基于Atlas地图使用
  • 原文地址:https://www.cnblogs.com/qiuxiangmuyu/p/5843152.html
Copyright © 2011-2022 走看看