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