協程
介紹
- 不是進程或線程,執行過程類似於子例程或者說不帶返回值的函數調用。
- 達到類似多線程的併發執行效果
- 在yield return 處移交控制權。
- 可以提前結束執行
使用
- 聲明方式
- IEnumerator [methodName] (){yield return XXX }
- IEnumerator [methodName] (){yield return T }
開啓方式
- public Coroutine StartCoroutine(IEnumerator methodName());
- public Coroutine StartCoroutine(string methodName);
- public Coroutine StartCoroutine(string methodName, [DefaultValue(“null”)] object value);
StartCoroutine會立即執行開啓傳入的協程並返回一個Coroutine類型。
結束方式
- public void StopCoroutine(IEnumerator methodName());
- public void StopCoroutine(string methodName);
public void StopCoroutine(Coroutine routine);
前兩種結束方式根據參數類型分別對應開啓方式的三種,第三種結束方式傳入參數爲StartCoroutine所返回的Coroutine類型實例。
內部結束執行
yield break;
執行順序:開啓協程後會立即開始執行協程中的命令,直到遇到第一個yield return 時會暫時把控制權移交出去並繼續執行其它代碼,此時這個協程在這一幀中已經無法繼續往下執行了,下一幀開始後根據生命週期函數的執行順序去訪問一次協程,如果可以則會從上次yield return的地方繼續往下執行,以此類推。
關於協程中各類yield return在一幀中執行的順序可以查閱Unity目錄下的Editor/Data/Documentation/en/Manual/ExecutionOrder.html的生命週期圖,也可通過Unity內幫助進行訪問。
協程本質
協程的本質是迭代器,它們被封裝在IEnumerator,IEnumerable以及他們倆的泛型形式IEnumerator,IEnumerable之中。其中IEnumerator還實現了IDisposable接口。
public interface IEnumerator
{
object Current { get; }
bool MoveNext();
void Reset();
}
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
public interface IEnumerator : IEnumerator, IDisposable
{
T Current { get; }
}
public interface IEnumerable : IEnumerable
{
IEnumerator GetEnumerator();
}
public interface IDisposable
{
void Dispose();
}IEnumerable 用來獲取一個迭代器(IEnumerator),而迭代工作實際在IEnumerator中實現,這一過程可以通過代碼來模擬完成。
- 執行一個協程IEnumerator,將返回得到一個新類型實例 ,循環執行該實例的MoveNext方法,如果MoveNext返回true則打印出該實例的屬性Current,這樣可以看到在協程中yield return的值都被依次打印出來,這就是foreach方法所執行的大概過程。
- IEnumerable提供了一個GetEnumerator的方法用來獲取迭代器。
3.協程中所返回的值被迭代器保存在堆上以便後面繼續使用,每次調用MoveNext()方法時會從上次yield return的地方繼續。 - 其實迭代器這種設計在多種主流語言中都可見到,如Java,ECMAScript,Python等,通常多使用於集合類數據結構的遍歷。
迭代器是什麼
- 迭代器工作原理是使用狀態機,在迭代器創建完一個新類型且一次未調用MoveNext前,狀態機的狀態爲0(初始狀態),
- 此後在迭代器每次狀態改變前的狀態都會被重置爲-1(預備狀態/結束狀態),
- 然後執行過程中的代碼並記錄當前返回值,在一系列狀態完成之後狀態會依次變爲1,2,3,4…(完成狀態)以便記錄所執行到的位置。
- 另外,由於IEnumerable還需額外執行GetEnumerator方法來獲取到IEnumerator,狀態機用-2(轉接狀態)來標記這一階段的狀態
參考資料:
- 《使用C#語言開發跨平臺遊戲》—陳嘉棟
- Unity官方文檔