2015年7月23日 星期四

協程Coroutine簡介

<概述>

Coroutine是Unity內建的一個延遲處理技巧, 透過這個技巧, 您可以輕易做出各種延遲處理的程式.

舉例來說:
0. 循環執行, 例如: 每秒呼叫某個函式1次
1. 程式中常常會需要的, delay call, 例如: 我希望玩家按了鈕後3秒才呼叫某個函式
2. 順暢不卡畫面的讀取條
3. 非常簡陋的loop, 卻可以透過Coroutine讓他花10秒鐘才完成

簡而言之, 學會Coroutine, 您可以合法使用Unity的單執行緒去做到有點類似多執行緒才能辦到的事情, 請特別注意, Coroutine本身是單執行緒的, 他只是利用程式技巧來辦到延遲執行.


<來歷>

Coroutine的程式概念, 在1958年由Melvin Edward Conway提出, 是一種類似多執行緒的單執行緒程式概念, 且可以避開多執行緒的race condition問題, 因為他是單執行緒!!!, 所以不會有第二個執行緒來搶著操作.

<概念>

以下我們用一個簡單的例子來了解Coroutine

假設現在我們將操場跑一圈, 視為Unity MonoBehaviour的一次update生命週期
為了遊戲畫面的順利, 我們會需要持續在這個操場上跑

此時我們會在操場上的某個地方出現一個拼圖任務, 這拼圖是兩萬片等級的, 根本不可能瞬間拼好, 所以一般程式跑到這邊時, 就只能讓畫面停下來專心去完成拼圖任務, 因此畫面就會出現嚴重的卡頓, 嚴重一點就像當機了一樣

這時Coroutine出現了, 他扮演的角色是一張桌子, 讓我們可以把拼圖的工作放到這張桌子上進行, 而因為有桌子替我們把拼圖工作收好, 所以我們可以選擇每圈只拼個幾片拼圖就繼續往前跑, 如此一來, 玩家的畫面將不會因為這個拼圖工作而出現嚴重的卡頓情況

Coroutine差不多就是這樣, 提供一個合法的容器, 將我們要處理的工作進行分期處理

<簡單實做>

以下我們提供一個最簡單的Coroutine範例

IEnumerator MyCoroutineFunction(string myStr)
{
    print("這行只會在函式被呼叫的時候執行");

    /*
    * 接下來的5秒內, new出來的WaitForSecounds物件
    * 都會持續回傳null, 接著程式會透過IEnumerator 和yield 功能
    * 暫時離開這個函式, 繼續做其他該做的事情, 直到下個update後
    * 程式會直接回到這行, 持續反覆這樣的動作
    * 直到WaitForSecounds回傳不是null的值為止
    */
    yield return new WaitForSecounds(5);

    print("這行只會在上面條件達成後執行");
}

如何啟動做好的Coroutine呢?
StartCoroutine(MyCoroutineFunction("abc"));

這樣我們就簡單完成了一個長達5秒鐘的coroutine

<進階實做>

Coroutine的強大就在於, 他不但可以函式做一半跑掉
甚至連迴圈也可以做一半跑掉, 所以這裡我們要示範的
是一個花10秒才能完成的超慢for迴圈寫法
希望透過這個範例, 能夠讓您更清楚了解Coroutine的強大

IEnumerator MyCoroutineFunction2()
{
    print("這行只會在程式進入函式時被執行一次");
 
    for(var i = 0; i < 10; i++)
    {
        print("開始處理第" + i + "個訊息輸出");
        yield return new WaitForSecounds(1);//Coroutine會直接在這個地方暫時離開函式或回到函
        print("第" + i + "個訊息輸出後, 1秒鐘才會輸出這行");
    }
    print("這行訊息只會在上面迴圈跑完以後才輸出一次");
}

啟動方法是完全相同的
StartCoroutine(MyCoroutineFunction2());

最後補充概念圖:

1 則留言: