【Unity3D/C#】Unity3D中的Coroutine詳解

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

相關文章
相關標籤/搜索