Unity3D中的線程與協程

線程 

  Unity3D是以生命週期主線程循環進行遊戲開發。html

  Unity3D中的子線程沒法運行Unity SDK(開發者工具包,軟件包、軟件框架)跟API(應用程序編程接口,函數庫)。編程

  限制緣由:大多數遊戲引擎都是主循環結構,遊戲中邏輯更新和畫面更新的時間點要求有肯定性,必須按照幀序列嚴格保持同步,不然就會出現遊戲中的對象不一樣步的現象。雖然多線程也能保證這個效果,可是引用多線程,會加大同步處理的難度與遊戲的不穩定性。c#

  可是多線程也是有好處的,若是不是畫面更新,也不是常規的邏輯更新(指包括AI、物理碰撞、角色控制這些),而是一些其餘後臺任務,好比大量耗時的數據計算、網絡請求、複雜密集的I/O操做,則能夠將這個獨立出來作成一個工做線程,這須要寫Unity遊戲的Native擴展。網絡

協程

  對於Unity3D,它是生命週期主線程循環的設計,它更傾向於使用Time slicing(時間分片)的Coroutine(協程)去完成異步任務,融合到生命週期中。多線程

  線程是操做系統級別的概念,現代操做系統都支持並實現線程,線程的調度對應用開發者是透明的,開發者沒法預期某線程在什麼時候被調度執行。基於此,通常那種隨機出現的BUG,多與線程調度相關。框架

  而協程Coroutine是編譯器級別的,本質是一個線程時間片去執行代碼段。它經過相關的代碼使得代碼段可以實現分段式的執行,顯式調用yield函數後才被掛起,從新開始的地方是yield掛起的位置,每一次執行協程會跑到下一個yield語句。協程能保留上一次調用時的狀態(即全部局部狀態的一個特定組合),每次過程重入時,就至關於進入上一次調用的狀態,換種說法:進入上一次離開時所處邏輯流的位置。異步

  在Unity3D中,協程是可自行中止運行 (yield),直到給定的 YieldInstruction 結束再繼續運行的函數。協程 (Coroutines) 的不一樣用途: ·函數

       (1) yield return null - 這一幀到此暫停,下一幀再從暫停處繼續,經常使用於循環中。工具

       (2) yield return new WaitForEndOfFrame - 等到這一幀的cameras和GUI渲染結束後再今後處繼續,即等到這幀的末尾再往下運行。這行以後的代碼仍是在當前幀運行,是在下一幀開始前執行,跟return null很類似。oop

       (3) yield return new WaitForFixedUpdate - 在下一次執行FixedUpdate的時候繼續執行這段代碼,即等一次物理引擎的更新。

       (4) yield return new WaitForSeconds(3.0f) - 等待3秒,而後繼續今後處開始,經常使用於作定時器。

       (5) yield return WWW - 等待直至異步下載完成。

       (6) yield return StartCoroutine(methodName) - 等待另外一個協程執行完。這是把協程串聯起來的關鍵,經常使用於讓多個協程按順序逐個運行。

  (7)yield break - 直接跳出協程,對某些斷定失敗必須跳出的時候,好比加載AssetBundle的時候,WWW失敗了,後邊加載bundle沒有必要了,這時候能夠yield break跳出。

  值得注意的是 WaitForSeconds()受Time.timeScale影響,當Time.timeScale = 0f 時,yield return new WaitForSecond(x) 將不會知足。

 

  如下爲Unity3D的生命週期循環圖

c#代碼示例

Unity3D使用協程常須要用到輔助類Stopwatch,提供一組可用於準確地測量運行時間的方法和屬性。

private Stopwatch frameStopwatch;//用來記錄上一幀結束到如今所用的時間
private float targetFrameDuration;//自定義的每幀持續時間,防止協程過分消耗線程時間片
private void Awake()
{
    frameStopwatch = new Stopwatch();
}

void Update()
{
    //計算每一幀所用的時間Start()以後Elapsed會一直增長,Stop()以後Elapsed的值就不變
    frameStopwatch.Stop();
    frameStopwatch.Reset();
    frameStopwatch.Start();

  if(ChunkUpdateList.Count > 0)
  {
    StartCoroutine(ProcessChunkQueueLoop());//啓動協程處理ChunkUpdateList
  } }

private IEnumerator ProcessChunkQueueLoop()
{
    while (ChunkUpdateList.Count > 0)
    {
        ProcessChunkUpdateList();//每次處理ChunkUpdateList中的一個數據
        if (frameStopwatch.Elapsed.TotalSeconds >= targetFrameDuration)//這一幀已經運行的時間frameStopwatch.Elapsed.TotalSeconds已經超過自定義每幀的時間targetFrameDuration,則掛起直到這一幀結束再運行
        {
            yield return new WaitForEndOfFrame();
        }
    }
}

 

引用:

  (1)遊戲引擎Unity中的單線程與多線程

其餘:

  (1)遊戲主循環

  (2)3D引擎多線程:渲染與邏輯分離

相關文章
相關標籤/搜索