日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Unity协程(Coroutine)原理深入剖析再续

發布時間:2024/4/15 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Unity协程(Coroutine)原理深入剖析再续 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Unity協程(Coroutine)原理深入剖析再續

?

?By D.S.Qiu

尊重他人的勞動,支持原創,轉載請注明出處:http.dsqiu.iteye.com

? ? ? ??

? ? ? ? 前面已經介紹過對協程(Coroutine)的認識和理解,主要講到了Unity引擎在執行協程(Coroutine)的原理(Unity協程(Coroutine)原理深入剖析)和對協程(Coroutine)狀態的控制(Unity協程(Coroutine)管理類——TaskManager工具分享),到這使用Coroutine的疑問就沒有了,但是D.S.Qiu還是有點沒嚼爛,所以覺得很有必要再續。

? ? ? ? 本文主要分為三部分:

? ? ? ? ? ? ? ?1)yield return, IEnumerator ?和 Unity StartCoroutine 的關系和理解

? ? ? ? ? ? ???2)Cortoutine 擴展——Extending Coroutines: Return Values and Error Handling

? ? ? ? ? ? ? ?3)Cortountine Locking

?

? ? ? ? ?總之,引用③的一句話:Coroutines – More than you want to know.

? ? ? ? ?

1)yield return, IEnumerator ?和 Unity StartCoroutine 的關系和理解

? ? ? ? ? yield 和 IEnumerator都是C#的東西,前者是一個關鍵字,后者是枚舉類的接口。對于IEnumerator 只引用②對 IEnumerable與IEnumerator區別 的論述:

先貼出 IEnumerable 和 IEnumerator的定義:

C#代碼??
  • public?interface?IEnumerable??
  • {??
  • ????IEnumerator?GetEnumerator();??
  • }??
  • ???
  • public?interface?IEnumerator??
  • {??
  • ????bool?MoveNext();??
  • ????void?Reset();??
  • ???
  • ????Object?Current?{?get;?}??
  • }??
  • ?IEnumerable和IEnumerator有什么區別?這是一個很讓人困惑的問題(在很多forum里都看到有人在問這個問題)。研究了半天,得到以下幾點認識:

    ? ? ? ? ?1、一個Collection要支持foreach方式的遍歷,必須實現IEnumerable接口(亦即,必須以某種方式返回IEnumerator object)。

    ? ? ? ? ?2、IEnumerator object具體實現了iterator(通過MoveNext(),Reset(),Current)。

    ? ? ? ? ?3、從這兩個接口的用詞選擇上,也可以看出其不同:IEnumerable是一個聲明式的接口,聲明實現該接口的class是“可枚舉(enumerable)”的,但并沒有說明如何實現枚舉器(iterator);IEnumerator是一個實現式的接口,IEnumerator object就是一個iterator。

    ? ? ? ? ?4、IEnumerable和IEnumerator通過IEnumerable的GetEnumerator()方法建立了連接,client可以通過IEnumerable的GetEnumerator()得到IEnumerator object,在這個意義上,將GetEnumerator()看作IEnumerator object的factory method也未嘗不可。

    ?

    IEnumerator ?是所有枚舉數的基接口。 ??

    ? ? ? ? ?枚舉數只允許讀取集合中的數據。枚舉數無法用于修改基礎集合。 ??

    ? ? ? ? ?最初,枚舉數被定位于集合中第一個元素的前面。Reset ? 也將枚舉數返回到此位置。在此位置,調用 ? Current ? 會引發異常。因此,在讀取 ? Current ? 的值之前,必須調用 ? MoveNext ? 將枚舉數提前到集合的第一個元素。 ??

    ? ? ? ? ?在調用 ? MoveNext ? 或 ? Reset ? 之前,Current ? 返回同一對象。MoveNext ? 將 ? Current ? 設置為下一個元素。 ??

    ? ? ? ? ?在傳遞到集合的末尾之后,枚舉數放在集合中最后一個元素后面,且調用 ? MoveNext ? 會返回 ? false。如果最后一次調用 ? MoveNext ? 返回 ? false,則調用 ? Current ? 會引發異常。若要再次將 ? Current ? 設置為集合的第一個元素,可以調用 ? Reset,然后再調用 ? MoveNext。 ??

    ? ? ? ? ?只要集合保持不變,枚舉數就將保持有效。如果對集合進行了更改(例如添加、修改或刪除元素),則該枚舉數將失效且不可恢復,并且下一次對 ? MoveNext ? 或 ? Reset ? 的調用將引發 ? InvalidOperationException。如果在 ? MoveNext ? 和 ? Current ? 之間修改集合,那么即使枚舉數已經無效,Current ? 也將返回它所設置成的元素。 ??

    ? ? ? ? ?枚舉數沒有對集合的獨占訪問權;因此,枚舉一個集合在本質上不是一個線程安全的過程。甚至在對集合進行同步處理時,其他線程仍可以修改該集合,這會導致枚舉數引發異常。若要在枚舉過程中保證線程安全,可以在整個枚舉過程中鎖定集合,或者捕捉由于其他線程進行的更改而引發的異常。

    ?

    Yield關鍵字

    在迭代器塊中用于向枚舉數對象提供值或發出迭代結束信號。它的形式為下列之一⑥:

      yield return <expression_r>;

      yield break;

    備注 :

      計算表達式并以枚舉數對象值的形式返回;expression_r 必須可以隱式轉換為迭代器的 yield 類型。

      yield 語句只能出現在 iterator 塊中,該塊可用作方法、運算符或訪問器的體。這類方法、運算符或訪問器的體受以下約束的控制:

      不允許不安全塊。

      方法、運算符或訪問器的參數不能是 ref 或 out。

      yield 語句不能出現在匿名方法中。

      當和 expression_r 一起使用時,yield return 語句不能出現在 catch 塊中或含有一個或多個 catch 子句的 try 塊中。

    ?

      yield return 提供了迭代器一個比較重要的功能,即取到一個數據后馬上返回該數據,不需要全部數據裝入數列完畢,這樣有效提高了遍歷效率。

    ?

    Unity StartCoroutine

    ? ? ? Unity使用 StartCoroutine(routine: IEnumerator): Coroutine 啟動協程,參數必須是 IEnumerator 對象。那么Unity在背后做什么神奇的處理呢?

    ? ? ? StartCoroutine函數的參數我一般都是通過傳入一個返回值為 IEnumerator的函數得到的:

    C#代碼??
  • IEnumerator?WaitAndPrint(float?waitTime)?{??
  • ????yield?return?new?WaitForSeconds(waitTime);??
  • ????print("WaitAndPrint?"?+?Time.time);??
  • }??
  • ? ? ? ?在函數內使用前面介紹?yield 關鍵字返回 IEnumerator 對象,Unity 中實現了 YieldInstruction 作為 yield 返回的基類,有 Cortoutine, WaitForSecondes, WaitForEndOfFrame, WaitForFixedUpdate, WWW 幾個子類實現。StartCoroutine 將 傳入的 IEnumerator 封裝為 Coroutine 返回,引擎會對 Corountines 存儲和檢查 IEnumerator 的 Current值。

    ?

    ③枚舉了 WWW ,WaitForSeconds , null 和 WaitForEndOfFrame 檢查 Current值在MonoBebaviour生存周期的時間(沒有WaitForFixedUpdate ,D.S.Qiu猜測是其作者成文是Unity引擎還沒有提供這個實現):

    ?

    ? ? ? ?WWW - after Updates happen for all game objects; check the isDone flag. If true, call the IEnumerator's MoveNext() function;

    ? ? ? ?WaitForSeconds - after Updates happen for all game objects; check if the time has elapsed, if it has, call MoveNext();

    ? ? ? ?null or some unknown value - after Updates happen for all game objects; Call MoveNext();

    ? ? ? ?WaitForEndOfFrame - after Render happens for all cameras; Call MoveNext().

    ?

    如果最后一個 yield return 的 IEnumerator 已經迭代到最后一個是,MoveNext 就會 返回 false 。這時,Unity就會將這個 IEnumerator 從 cortoutines list 中移除。

    ?

    ? ? ? ?所以很容易一個出現的誤解:協程 Coroutines 并不是并行的,它和你的其他代碼都運行在同一個線程中,所以才會在Update 和 Coroutine中使用 同一個值時才會變得線程安全。這就是Unity對線程安全的解決策略——直接不使用線程,最近Unity 5 將要發布說的很熱,看到就有完全多線程的支持,不知道是怎么實現的,從技術的角度,還是很期待的哈。

    ?

    ? ? ? ?總結下: 在協程方法中使用 yield return 其實就是為了返回 IEnumerator對象,只有當這個對象的 MoveNext() 返回 false 時,即該 IEnumertator 的 Current 已經迭代到最后一個元素了,才會執行 yield return 后面的語句。也就是說, yield return 被會“翻譯”為一個 IEnmerator 對象,要想深入了解這方面的更多細節,可以猛擊⑤查看。

    ? ? ? ?根據⑤ C# in depth 的理解——C# 編譯器會生成一個 IEnumerator 對象,這個對象實現的 MoveNext() 包含函數內所有 yield return 的處理,這里僅附上一個例子:

    C#代碼??
  • using?System;??
  • using?System.Collections;??
  • ??
  • class?Test??
  • {??
  • ????static?IEnumerator?GetCounter()??
  • ????{??
  • ????????for?(int?count?=?0;?count?<?10;?count++)??
  • ????????{??
  • ????????????yield?return?count;??
  • ????????}??
  • ????}??
  • }??
  • ?C#編譯器對應生成:

    Cpp代碼??
  • internal?class?Test??
  • {??
  • ????//?Note?how?this?doesn't?execute?any?of?our?original?code??
  • ????private?static?IEnumerator?GetCounter()??
  • ????{??
  • ????????return?new?<GetCounter>d__0(0);??
  • ????}??
  • ??
  • ????//?Nested?type?automatically?created?by?the?compiler?to?implement?the?iterator??
  • ????[CompilerGenerated]??
  • ????private?sealed?class?<GetCounter>d__0?:?IEnumerator<object>,?IEnumerator,?IDisposable??
  • ????{??
  • ????????//?Fields:?there'll?always?be?a?"state"?and?"current",?but?the?"count"??
  • ????????//?comes?from?the?local?variable?in?our?iterator?block.??
  • ????????private?int?<>1__state;??
  • ????????private?object?<>2__current;??
  • ????????public?int?<count>5__1;??
  • ??
  • ????????[DebuggerHidden]??
  • ????????public?<GetCounter>d__0(int?<>1__state)??
  • ????????{??
  • ????????????this.<>1__state?=?<>1__state;??
  • ????????}??
  • ??
  • ????????//?Almost?all?of?the?real?work?happens?here??
  • ????????private?bool?MoveNext()??
  • ????????{??
  • ????????????switch?(this.<>1__state)??
  • ????????????{??
  • ????????????????case?0:??
  • ????????????????????this.<>1__state?=?-1;??
  • ????????????????????this.<count>5__1?=?0;??
  • ????????????????????while?(this.<count>5__1?<?10)????????//這里針對循環處理??
  • ????????????????????{??
  • ????????????????????????this.<>2__current?=?this.<count>5__1;??
  • ????????????????????????this.<>1__state?=?1;??
  • ????????????????????????return?true;??
  • ????????????????????Label_004B:??
  • ????????????????????????this.<>1__state?=?-1;??
  • ????????????????????????this.<count>5__1++;??
  • ????????????????????}??
  • ????????????????????break;??
  • ??
  • ????????????????case?1:??
  • ????????????????????goto?Label_004B;??
  • ????????????}??
  • ????????????return?false;??
  • ????????}??
  • ??
  • ????????[DebuggerHidden]??
  • ????????void?IEnumerator.Reset()??
  • ????????{??
  • ????????????throw?new?NotSupportedException();??
  • ????????}??
  • ??
  • ????????void?IDisposable.Dispose()??
  • ????????{??
  • ????????}??
  • ??
  • ????????object?IEnumerator<object>.Current??
  • ????????{??
  • ????????????[DebuggerHidden]??
  • ????????????get??
  • ????????????{??
  • ????????????????return?this.<>2__current;??
  • ????????????}??
  • ????????}??
  • ??
  • ????????object?IEnumerator.Current??
  • ????????{??
  • ????????????[DebuggerHidden]??
  • ????????????get??
  • ????????????{??
  • ????????????????return?this.<>2__current;??
  • ????????????}??
  • ????????}??
  • ????}??
  • }??
  • ? ? ? ?從上面的C#實現可以知道:函數內有多少個 yield return 在對應的 MoveNext() 就會返回多少次 true (不包含嵌套)。另外非常重要的一點的是:同一個函數內的其他代碼(不是 yield return 語句)會被移到 MoveNext 中去,也就是說,每次 MoveNext 都會順帶執行同一個函數中 yield return 之前,之后 和兩個 yield return 之間的代碼。

    ? ? ? ?對于Unity 引擎的 YieldInstruction 實現,其實就可以看著一個 函數體,這個函數體每幀會實現去 check MoveNext 是否返回 false 。 例如:

    C#代碼??
  • yield?retrun?new?WaitForSeconds(2f);??
  • ? ? ? ?上面這行代碼的偽代碼實現:

    C#代碼??
  • private?float?elapsedTime;??
  • private?float?time;??
  • ??
  • private?void?MoveNext()??
  • {??
  • ????????elapesedTime?+=?Time.deltaTime;??
  • ??????????
  • ????????if(time?<=?elapsedTime)??
  • ????????????????return?false;??
  • ????????else?return?true;??
  • ??
  • }??
  • ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?增補于: 2014年04月22日 8:00

    ?

    ?2)Cortoutine 擴展——Extending Coroutines: Return Values and Error Handling

    ? ? ? ? 不知道你們調用 StartCortoutine 的時候有沒有注意到 StartCortoutine 返回了 YieldInstruction 的子類 Cortoutine 對象,這個返回除了嵌套使用 StartCortoutine 在 yiled retrun StartCortoutine 有用到,其他情況機會就沒有考慮它的存在,反正D.S.Qiu是這樣的,一直認為物“極”所用,所以每次調用 StartCortoutine 都很糾結,好吧,有點強迫癥。

    ? ? ? ?Unity引擎講 StartCoroutine 傳入的參數 IEnumerator 封裝為一個 Coroutine 對象中,而 Coroutine 對象其實也是 IEnumerator 枚舉對象。yield return 的 IEnumerator 對象都存儲在這個 Coroutine 中,只有當上一個yield return 的 IEnumerator 迭代完成,才會運行下一個。這個在猜測下Unity底層對Cortountine 的統一管理(也就是上面說的檢查 Current 值):Unity底層應該有一個 正在運行的 Cortoutine 的 list 然后在每幀的不同時間去 Check。

    ?

    ? ? ? ? 還是回歸到主題,上面介紹 yield 關鍵字有說不允許不安全塊,也就是說不能出現在 try catch 塊中,就不能在 yield return 執行是進行錯誤檢查。③利用 StartCortoutine 返回值 Cortoutine 得到了當前的 Current 值和進行錯誤捕獲處理。

    先定義封裝包裹返回值和錯誤信息的類:

    C#代碼??
  • public?class?Coroutine<T>{??
  • public?T?Value?{??
  • ????get{??
  • ????????if(e?!=?null){??
  • ????????????throw?e;??
  • ????????}??
  • ????????return?returnVal;??
  • ????}??
  • }??
  • private?T?returnVal;??//當前迭代器的Current?值??
  • private?Exception?e;????//拋出的錯誤信息??
  • public?Coroutine?coroutine;??
  • ??
  • public?IEnumerator?InternalRoutine(IEnumerator?coroutine){??
  • ????//先省略這部分的處理??
  • ????}??
  • }??
  • ?InteralRoutine是對返回 Current 值和拋出的異常信息(如果有的話):

    C#代碼??
  • public?IEnumerator?InternalRoutine(IEnumerator?coroutine){??
  • ????while(true){??
  • ????????try{??
  • ????????????if(!coroutine.MoveNext()){??
  • ????????????????yield?break;??
  • ????????????}??
  • ????????}??
  • ????????catch(Exception?e){??
  • ????????????this.e?=?e;??
  • ????????????yield?break;??
  • ????????}??
  • ????????object?yielded?=?coroutine.Current;??
  • ????????if(yielded?!=?null?&&?yielded.GetType()?==?typeof(T)){??
  • ????????????returnVal?=?(T)yielded;??
  • ????????????yield?break;??
  • ????????}??
  • ????????else{??
  • ????????????yield?return?coroutine.Current;??
  • ????????}??
  • ????}??
  • ?下面為這個類擴展MonoBehavior:

    C#代碼??
  • public?static?class?MonoBehaviorExt{??
  • ????public?static?Coroutine<T>?StartCoroutine<T>(this?MonoBehaviour?obj,?IEnumerator?coroutine){??
  • ????????Coroutine<T>?coroutineObject?=?new?Coroutine<T>();??
  • ????????coroutineObject.coroutine?=?obj.StartCoroutine(coroutineObject.InternalRoutine(coroutine));??
  • ????????return?coroutineObject;??
  • ????}??
  • }??
  • ?最后給出一個 Example:

    C#代碼??
  • IEnumerator?Start?()?{??
  • ????????var?routine?=?StartCoroutine<int>(TestNewRoutine());?//Start?our?new?routine??
  • ????????yield?return?routine.coroutine;?//?wait?as?we?normally?can??
  • ????????Debug.Log(routine.Value);?//?print?the?result?now?that?it?is?finished.??
  • ????}??
  • ??????
  • ????IEnumerator?TestNewRoutine(){??
  • ????????yield?return?null;??
  • ????????yield?return?new?WaitForSeconds(2f);??
  • ????????yield?return?10;??
  • ????????????????yield?return?5;??
  • ????}??
  • ?最后輸出是10,因為Cortoutine<T> 遇到滿足條件的 T 類型就 執行 yield break;就不執行 yield return 5; 這條語句了。

    如果將中 yield break; 語句去掉的話,最后輸出的是 5 而不是10。

    C#代碼??
  • if(yielded?!=?null?&&?yielded.GetType()?==?typeof(T)){??
  • ????????????returnVal?=?(T)yielded;??
  • ????????????yield?break;??
  • ????????}??

  • 其實就是Unity引擎每幀去 check yield return 后面的表達式,如果滿足就繼續向下執行。

    ?

    下面在測試一個例子:連續兩次調用 yield return coroutine;

    C#代碼??
  • ?private?Coroutine?routine1;??
  • ?void?Start?()???
  • ?{??
  • ????routine1?=?StartCoroutine(TestCoroutineExtention1());?//Start?our?new?routine????
  • ????StartCoroutine(TestCortoutine());??
  • ??????
  • }??
  • IEnumerator?TestCoroutineExtention1()??
  • {??
  • ????yield?return?new?WaitForSeconds(1);??
  • ????yield?return?10;??
  • ????Debug.Log("Run?10!");??
  • ????yield?return?new?WaitForSeconds(5);??
  • ????yield?return?5;??
  • ????Debug.Log("Run?5!");??
  • }??
  • IEnumerator?TestCortoutine()??
  • {??
  • ????//wwwState?=?true;??
  • ????yield?return?routine1;?//?wait?as?we?normally?can????
  • ????Debug.Log("?routine1");??
  • ????yield?return?routine1;?//?wait?as?we?normally?can???
  • ????Debug.Log("?routine2");??
  • }??
  • ?測試運行會發現只會輸出:

    ? ? ? ? Run 10!

    ? ? ? ? Run 5!

    ? ? ? ? ?routine1

    ?

    總結下: yield return expression 只有表達式完全執行結束才會繼續執行后面的代碼,連續兩次執行 yield return StartCortoutine() 的返回值是不會滿足的,說明 yield return 有區分開始和結束的兩種狀態。

    ?

    ?

    3)Cortoutine Locking

    ? ? ? ? ? 雖然Cortoutine不是多線程機制,但仍會“并發”問題——同時多次調用 StartCortoutine ,當然通過Unity提供的api也能得到解決方案,每次StartCoroutine 之前先調用 StopCortoutine 方法停止,但這利用的是反射,顯然效率不好。④對③的方案進行了擴展提供了 Cortoutine Locking 的支持,使用字符串(方法名)來標記同一個 Coroutine 方法,對于同一個方法如果等待時間超過 timeout 就會終止前面一個 Coroutine 方法,下面直接貼出代碼:

    C#代碼??
  • using?UnityEngine;??
  • using?System;??
  • using?System.Collections;??
  • using?System.Collections.Generic;??
  • ??
  • ///?<summary>??
  • ///?Extending?MonoBehaviour?to?add?some?extra?functionality??
  • ///?Exception?handling?from:?http://twistedoakstudios.com/blog/Post83_coroutines-more-than-you-want-to-know??
  • ///???
  • ///?2013?Tim?Tregubov??
  • ///?</summary>??
  • public?class?TTMonoBehaviour?:?MonoBehaviour??
  • {??
  • ????private?LockQueue?LockedCoroutineQueue?{?get;?set;?}??
  • ??????????????
  • ????///?<summary>??
  • ????///?Coroutine?with?return?value?AND?exception?handling?on?the?return?value.???
  • ????///?</summary>??
  • ????public?Coroutine<T>?StartCoroutine<T>(IEnumerator?coroutine)??
  • ????{??
  • ????????Coroutine<T>?coroutineObj?=?new?Coroutine<T>();??
  • ????????coroutineObj.coroutine?=?base.StartCoroutine(coroutineObj.InternalRoutine(coroutine));??
  • ????????return?coroutineObj;??
  • ????}??
  • ??????
  • ????///?<summary>??
  • ????///?Lockable?coroutine.?Can?either?wait?for?a?previous?coroutine?to?finish?or?a?timeout?or?just?bail?if?previous?one?isn't?done.??
  • ????///?Caution:?the?default?timeout?is?10?seconds.?Coroutines?that?timeout?just?drop?so?if?its?essential?increase?this?timeout.??
  • ????///?Set?waitTime?to?0?for?no?wait??
  • ????///?</summary>??
  • ????public?Coroutine<T>?StartCoroutine<T>(IEnumerator?coroutine,?string?lockID,?float?waitTime?=?10f)??
  • ????{??
  • ????????if?(LockedCoroutineQueue?==?null)?LockedCoroutineQueue?=?new?LockQueue();??
  • ????????Coroutine<T>?coroutineObj?=?new?Coroutine<T>(lockID,?waitTime,?LockedCoroutineQueue);??
  • ????????coroutineObj.coroutine?=?base.StartCoroutine(coroutineObj.InternalRoutine(coroutine));??
  • ????????return?coroutineObj;??
  • ????}??
  • ??????
  • ????///?<summary>??
  • ????///?Coroutine?with?return?value?AND?exception?handling?AND?lockable??
  • ????///?</summary>??
  • ????public?class?Coroutine<T>??
  • ????{??
  • ????????private?T?returnVal;??
  • ????????private?Exception?e;??
  • ????????private?string?lockID;??
  • ????????private?float?waitTime;??
  • ??????????
  • ????????private?LockQueue?lockedCoroutines;?//reference?to?objects?lockdict??
  • ????????private?bool?lockable;??
  • ??????????
  • ????????public?Coroutine?coroutine;??
  • ????????public?T?Value??
  • ????????{??
  • ????????????get???
  • ????????????{???
  • ????????????????if?(e?!=?null)??
  • ????????????????{??
  • ????????????????????throw?e;??
  • ????????????????}??
  • ????????????????return?returnVal;??
  • ????????????}??
  • ????????}??
  • ??????????
  • ????????public?Coroutine()?{?lockable?=?false;?}??
  • ????????public?Coroutine(string?lockID,?float?waitTime,?LockQueue?lockedCoroutines)??
  • ????????{??
  • ????????????this.lockable?=?true;??
  • ????????????this.lockID?=?lockID;??
  • ????????????this.lockedCoroutines?=?lockedCoroutines;??
  • ????????????this.waitTime?=?waitTime;??
  • ????????}??
  • ??????????
  • ????????public?IEnumerator?InternalRoutine(IEnumerator?coroutine)??
  • ????????{??
  • ????????????if?(lockable?&&?lockedCoroutines?!=?null)??
  • ????????????{?????????
  • ????????????????if?(lockedCoroutines.Contains(lockID))??
  • ????????????????{??
  • ????????????????????if?(waitTime?==?0f)??
  • ????????????????????{??
  • ????????????????????????//Debug.Log(this.GetType().Name?+?":?coroutine?already?running?and?wait?not?requested?so?exiting:?"?+?lockID);??
  • ????????????????????????yield?break;??
  • ????????????????????}??
  • ????????????????????else??
  • ????????????????????{??
  • ????????????????????????//Debug.Log(this.GetType().Name?+?":?previous?coroutine?already?running?waiting?max?"?+?waitTime?+?"?for?my?turn:?"?+?lockID);??
  • ????????????????????????float?starttime?=?Time.time;??
  • ????????????????????????float?counter?=?0f;??
  • ????????????????????????lockedCoroutines.Add(lockID,?coroutine);??
  • ????????????????????????while?(!lockedCoroutines.First(lockID,?coroutine)?&&?(Time.time?-?starttime)?<?waitTime)??
  • ????????????????????????{??
  • ????????????????????????????yield?return?null;??
  • ????????????????????????????counter?+=?Time.deltaTime;??
  • ????????????????????????}??
  • ????????????????????????if?(counter?>=?waitTime)??
  • ????????????????????????{???
  • ????????????????????????????string?error?=?this.GetType().Name?+?":?coroutine?"?+?lockID?+?"?bailing!?due?to?timeout:?"?+?counter;??
  • ????????????????????????????Debug.LogError(error);??
  • ????????????????????????????this.e?=?new?Exception(error);??
  • ????????????????????????????lockedCoroutines.Remove(lockID,?coroutine);??
  • ????????????????????????????yield?break;??
  • ????????????????????????}??
  • ????????????????????}??
  • ????????????????}??
  • ????????????????else??
  • ????????????????{??
  • ????????????????????lockedCoroutines.Add(lockID,?coroutine);??
  • ????????????????}??
  • ????????????}??
  • ??????????????
  • ????????????while?(true)??
  • ????????????{??
  • ????????????????try???
  • ????????????????{??
  • ????????????????????if?(!coroutine.MoveNext())??
  • ????????????????????{??
  • ????????????????????????if?(lockable)?lockedCoroutines.Remove(lockID,?coroutine);??
  • ????????????????????????yield?break;??
  • ????????????????????}??
  • ????????????????}??
  • ????????????????catch?(Exception?e)??
  • ????????????????{??
  • ????????????????????this.e?=?e;??
  • ????????????????????Debug.LogError(this.GetType().Name?+?":?caught?Coroutine?exception!?"?+?e.Message?+?"\n"?+?e.StackTrace);???
  • ????????????????????if?(lockable)?lockedCoroutines.Remove(lockID,?coroutine);??
  • ????????????????????yield?break;??
  • ????????????????}??
  • ??????????????????
  • ????????????????object?yielded?=?coroutine.Current;??
  • ????????????????if?(yielded?!=?null?&&?yielded.GetType()?==?typeof(T))??
  • ????????????????{??
  • ????????????????????returnVal?=?(T)yielded;??
  • ????????????????????if?(lockable)?lockedCoroutines.Remove(lockID,?coroutine);??
  • ????????????????????yield?break;??
  • ????????????????}??
  • ????????????????else??
  • ????????????????{??
  • ????????????????????yield?return?coroutine.Current;??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??????
  • ??????
  • ????///?<summary>??
  • ????///?coroutine?lock?and?queue??
  • ????///?</summary>??
  • ????public?class?LockQueue??
  • ????{??
  • ????????private?Dictionary<string,?List<IEnumerator>>?LockedCoroutines?{?get;?set;?}??
  • ??????????
  • ????????public?LockQueue()??
  • ????????{??
  • ????????????LockedCoroutines?=?new?Dictionary<string,?List<IEnumerator>>();??
  • ????????}??
  • ??????????
  • ????????///?<summary>??
  • ????????///?check?if?LockID?is?locked??
  • ????????///?</summary>??
  • ????????public?bool?Contains(string?lockID)??
  • ????????{??
  • ????????????return?LockedCoroutines.ContainsKey(lockID);??
  • ????????}??
  • ??????????
  • ????????///?<summary>??
  • ????????///?check?if?given?coroutine?is?first?in?the?queue??
  • ????????///?</summary>??
  • ????????public?bool?First(string?lockID,?IEnumerator?coroutine)??
  • ????????{??
  • ????????????bool?ret?=?false;??
  • ????????????if?(Contains(lockID))??
  • ????????????{??
  • ????????????????if?(LockedCoroutines[lockID].Count?>?0)??
  • ????????????????{??
  • ????????????????????ret?=?LockedCoroutines[lockID][0]?==?coroutine;??
  • ????????????????}??
  • ????????????}??
  • ????????????return?ret;??
  • ????????}??
  • ??????????
  • ????????///?<summary>??
  • ????????///?Add?the?specified?lockID?and?coroutine?to?the?coroutine?lockqueue??
  • ????????///?</summary>??
  • ????????public?void?Add(string?lockID,?IEnumerator?coroutine)??
  • ????????{??
  • ????????????if?(!LockedCoroutines.ContainsKey(lockID))??
  • ????????????{??
  • ????????????????LockedCoroutines.Add(lockID,?new?List<IEnumerator>());??
  • ????????????}??
  • ??????????????
  • ????????????if?(!LockedCoroutines[lockID].Contains(coroutine))??
  • ????????????{??
  • ????????????????LockedCoroutines[lockID].Add(coroutine);??
  • ????????????}??
  • ????????}??
  • ??????????
  • ????????///?<summary>??
  • ????????///?Remove?the?specified?coroutine?and?queue?if?empty??
  • ????????///?</summary>??
  • ????????public?bool?Remove(string?lockID,?IEnumerator?coroutine)??
  • ????????{??
  • ????????????bool?ret?=?false;??
  • ????????????if?(LockedCoroutines.ContainsKey(lockID))??
  • ????????????{??
  • ????????????????if?(LockedCoroutines[lockID].Contains(coroutine))??
  • ????????????????{??
  • ????????????????????ret?=?LockedCoroutines[lockID].Remove(coroutine);??
  • ????????????????}??
  • ??????????????????
  • ????????????????if?(LockedCoroutines[lockID].Count?==?0)??
  • ????????????????{??
  • ????????????????????ret?=?LockedCoroutines.Remove(lockID);??
  • ????????????????}??
  • ????????????}??
  • ????????????return?ret;??
  • ????????}??
  • ??????????
  • ????}??
  • ??
  • }??
  • ?

    小結:

    ? ? ? ?本文主要是對 Unity StartCoroutine 進行了理解,從C# 的yileld 和 IEnumerator 到 Unity 的 StartCoroutine,最后并對Cortoutine 進行了擴展,雖然感覺不是很實用(用到的情況非常至少),但還是有利于對Coroutine 的理解和思考。

    ? ? ? ?對于第三部分的代碼感覺有不妥,沒有進行測試,附件里有代碼,有需求的話請自取

    ?

    ? ? ? ? 如果您對D.S.Qiu有任何建議或意見可以在文章后面評論,或者發郵件(gd.s.qiu@gmail.com)交流,您的鼓勵和支持是我前進的動力,希望能有更多更好的分享。

    ? ? ? ?轉載請在文首注明出處:http://dsqiu.iteye.com/blog/2049743

    ?

    更多精彩請關注D.S.Qiu的博客和微博(ID:靜水逐風)?

    ?

    ?

    ?

    參考:

    ①琪琪爸的程序學習筆記 :-P:http://www.cnblogs.com/easyfrog/archive/2011/12/29/IEnumerable_IEnumerator_yield.html

    ②杰仔:http://www.cnblogs.com/illele/archive/2008/04/21/1164696.html

    ③Twisted Oak Studios:?http://twistedoakstudios.com/blog/Post83_coroutines-more-than-you-want-to-know

    ④tim tregubov:http://zingweb.com/blog/2013/02/05/unity-coroutine-wrapper/

    ⑤C# in Depth:?http://csharpindepth.com/articles/chapter6/iteratorblockimplementation.aspx

    zhw1125:?http://blog.sina.com.cn/s/blog_3e29b20b0100g6ix.html

    ?

    轉載于:https://www.cnblogs.com/Uinkanade/articles/3984676.html

    總結

    以上是生活随笔為你收集整理的Unity协程(Coroutine)原理深入剖析再续的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 久草久 | 依人在线| 日韩经典在线 | 噜噜噜噜噜色 | 国产精品毛片在线 | 国产又大又粗又爽的毛片 | 特级西西444www大胆免费看 | 精品无码国产一区二区三区av | av动漫天堂| 国产精品久久久久久免费免熟 | 亚洲调教欧美在线 | 美女黄站 | 国产一区二区网 | 超碰夜夜 | 啪啪福利 | 五月情网 | 日韩手机看片 | 日本黄色免费网站 | 欧美少妇一区 | wwwww在线观看 | 国产哺乳奶水91在线播放 | 日本中文字幕在线播放 | www激情com | 美女精品久久久 | 日本在线资源 | 99伊人网| 亚洲福利天堂 | 国产亚洲91| 色视频综合 | 国产成人精品亚洲日本在线观看 | 成人a站| 玖玖爱在线精品视频 | 91久久精品国产91性色69 | xxxx在线视频 | 午夜亚洲成人 | 午夜精品久久久久久久久久久 | 激情五月婷婷综合网 | 怡红院精品视频 | 亚洲国产欧美一区 | 中文字幕精品久久 | 亚洲va国产va天堂va久久 | 欧美群妇大交群 | 午夜久久久久久 | 国产学生美女无遮拦高潮视频 | 波多野结av衣东京热无码专区 | 在线香蕉 | 99久久精品免费看国产 | 日韩精品一区二区亚洲av性色 | 久久97精品| 中文字幕制服丝袜 | 国产免费av电影 | 亚洲va欧美va天堂v国产综合 | 九色91av| 中文字幕一区二区三区波野结 | 最新日韩av| 人人妻人人爽一区二区三区 | 日韩免费观看一区二区 | 秋霞一级全黄大片 | 国产精选视频在线观看 | 欧美成人综合 | 亚洲视频在线观看网站 | 日韩综合第一页 | 91猎奇在线观看 | 色欲亚洲Av无码精品天堂 | 波多一区二区 | 欧美八区 | 久久久久国产精品国产 | 精品无码av一区二区三区不卡 | v天堂在线观看 | 丝袜美腿av在线 | 人妻 日韩精品 中文字幕 | 色翁荡息又大又硬又粗又爽 | 丁香花完整视频在线观看 | 伊人av在线 | 日本一区不卡在线 | 午夜天堂在线观看 | 三级黄色在线 | 99国产精品白浆在线观看免费 | 美女狠狠干 | 老熟妇仑乱一区二区av | 国产强被迫伦姧在线观看无码 | 欧美乱插| 无码一区二区三区在线观看 | 捆绑束缚调教 | 一区二区三区视频播放 | 日本欧美国产在线 | 亚洲精品久久久中文字幕 | 特黄色一级片 | 欧美日韩国产在线一区 | 正在播放一区二区 | 国产一级免费在线观看 | 久久这里只有精品首页 | 欧洲精品无码一区二区 | 国产午夜精品无码 | 最近的中文字幕在线看视频 | 色婷婷色婷婷 | 亚洲精品无码一区二区 | 黄色三级在线播放 | 久久综合99|