Coroutine 協(xié)程

協(xié)程的關(guān)鍵字是 IEnumerator
這是迭代器的意思,那么什么是迭代器?

先請看下面的代碼:
定義一個Test類,實現(xiàn)IEnumerable接口:

    class Test : IEnumerable<string>
    {
        public IEnumerator<string> GetEnumerator()
        {
            for (int i = 0; i < 5; i++)
            {
                yield return "test" + i;
            }
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

說一下 IEnumerableIEnumerator 的關(guān)系:

  1. IEnumerable是一個接口,代表其是可枚舉的。
  2. IEnumerator對象就是一個迭代器(iterator:MoveNext(),Reset(),Current)。

用上面的類,寫一個測試程序:

            Test test = new Test();
            foreach (string s in test)
            {
                Console.WriteLine(s);
            }

此時輸出結(jié)果為:


輸出結(jié)果

可以猜到,輸出的就是 yield return xxx; 后面的xxx。
那么換一種寫法試試:

            Test test = new Test();
            var e = test.GetEnumerator();
            while (e.MoveNext())
            {
                Console.WriteLine(e.Current);
            }

這種寫法就是基于迭代器(iterator)的方式。先來看一下迭代器的定義:

    public interface IEnumerator
    {
        bool MoveNext();
        void Reset();
        Object Current {  get;  }
    }

從定義可以理解,使用foreach這樣的枚舉操作的時候,枚舉數(shù)被定為在集合的第一個元素前面。
使用迭代器在執(zhí)行迭代,首先會執(zhí)行 MoveNext(), 如果返回true,說明下一個位置有對象,然后此時將Current設(shè)置為下一個對象,這時候的Current就指向了下一個對象;如果返回false,說明下一個位置沒有對象,此時結(jié)束遍歷。

雖然看起來和遍歷數(shù)組一樣,但本質(zhì)上是把其包裝成了一個迭代器執(zhí)行,每次執(zhí)行到y(tǒng)ield的時候,程序就把需要的東西傳遞出去,再停住,不會繼續(xù)往下執(zhí)行。
由于這里yield下面沒有什么其他語句,所以就會依舊 i++ ,繼續(xù)執(zhí)行下去,然后又返回一個值。

那么回到Unity3d中,協(xié)程的用法如下:

        void Start()
        {
            StartCoroutine(DoSomething());
        }

        IEnumerator DoSomething()
        {
            DoBefore();
            yield return new WaitForSeconds(1f);
            DoAfter();
        }

這里Unity3d的運行效果,在 Start() 方法開啟協(xié)程后,程序會執(zhí)行 DoBefore() 函數(shù),直到遇見第一個yield,就會暫時把協(xié)程掛起,直到下一幀的Update渲染完成之后再獲取到迭代器當(dāng)前的 Current 對象,此時就是 WaitForSeconds 這個對象。
通過此對象,判斷是否還需要進行等待,再進行 DoAfter() 的回調(diào)。

我們可以寫偽代碼來表述內(nèi)部的邏輯:

void StartCoroutine(IEnumerator e)
{    
    if (!e.MoveNext())
    {        
        return;
    }    

    var obj = routine.Current;    
    if (obj is WaitForSeconds)
    {        
        //判斷是否到達時間 如果超過了設(shè)置時間 就繼續(xù)回調(diào)
    }
}

在注釋處,會利用現(xiàn)有的定時器機制,注冊定時器,并繼續(xù)進行 DoAfter() 的回調(diào)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容