Unity基礎-協程
四、協程
概述
協程(Coroutine),本質上并不是多線程,而是在當前線程中將代碼分時執行,不卡主線程。可以理解為,協程會把可能使主線程卡頓的程序分時分布進行。
協程通常用來:加載場景,異步加載文件,異步下載文件,批量創建物體防止卡頓。
協程與線程的區別
- 新開一個線程是獨立的一個管道,和主線程并行。Unity支持多線程,但是新開的線程無法訪問Unity中的任何東西,只能靠中間樞紐和Unity主線程聯絡。
- 新開一個協程是在原線程之上開啟,進行邏輯分時分布執行。
協程的使用
協程可以分為兩部分:1.協程函數本體,2.協程調度器。
協程本體就是一個能夠中間暫停返回的函數。協程調度器是Unity內部實現的,會在對應的時機幫助我們繼續執行協程函數。Unity只實現了協程調度的部分。
協同函數返回值必須是IEnumerator類型或者繼承他的類型。
// 聲明協程
IEnumerator MyCoroutineExample()
{print("111");yield return new WaitForSeconds(2);print("222");
}// 啟動協程
StartCoroutine(MyCoroutineExample());// 關閉全部協程
StopAllCoroutines(); // 關閉特定協程
Coroutine co1 = StartCoroutine(MyCoroutineExample());
StopCoroutine(co1);
協程函數本體與C#迭代器
協程的本體本質上就是一個C#迭代器的方法。
C# 迭代器(Iterator)是一種特殊的方法或 get
訪問器,允許你通過 yield return
語句逐步返回集合中的每個元素,而無需構建整個集合。它使得遍歷自定義集合類型變得非常簡單和高效。
IEnumerable
和 IEnumerable<T>
接口的作用是使一個類型能夠被 foreach
語句遍歷。簡單來說,只要一個類型實現了 IEnumerable
(或 IEnumerable<T>
),你就可以在 foreach
循環中使用它。
如果我們不通過Unity中給的開啟協程的方法開啟協程,Unity的協程調度器就不會幫我們管理協程函數。但是我們可以自己執行迭代器函數內容。
繼承MonoBehavior后,開啟協程,相當于把一個協程函數放入Unity的協程調度器中幫助我們管理進行執行,具體的 yield return
后面的規則也是Unity實現定義好的。
yield return
的含義和類型
yield return
語句是協程的核心,它控制協程的暫停和恢復時機,并可以返回不同類型的對象以實現不同的等待邏輯。
-
下一幀執行
yield return 數字;
(通常yield return 0;
或其他數字,但通常用null
)yield return null;
- 在
Update
和LateUpdate
之間執行。
-
等待指定秒后執行
yield return new WaitForSeconds(秒);
- 在
Update
和LateUpdate
之間執行。
-
等待下一個固定物理幀更新時執行
yield return new WaitForFixedUpdate();
- 在
FixedUpdate
和碰撞檢測相關函數之后執行。
-
等待攝像機和 GUI 渲染完成后執行
yield return new WaitForEndOfFrame();
- 在
LateUpdate
之后的渲染相關處理完畢后執行。
-
一些特殊類型的對象
- 比如異步加載相關函數返回的對象(
AsyncOperation
)。 - 通常在異步加載資源、異步加載場景、網絡加載時使用。
- 一般在
Update
和LateUpdate
之間執行。
- 比如異步加載相關函數返回的對象(
-
跳出協程
yield break;
:用于提前終止協程的執行。
協程應用示例:計時器與大量對象生成
習題要求
- 利用協程制作一個簡單的秒表計時器,每秒在控制臺打印當前秒數。
- 使用協程在場景中隨機位置生成100000個立方體,確保在生成過程中不會出現明顯的卡頓,這可以通過在適當的時機使用
yield return null;
實現。
代碼實現
點擊展開/折疊 協程實現代碼using System.Collections;
using UnityEngine;
using Random = UnityEngine.Random; // 明確指定Random命名空間,避免和System.Random沖突public class CoroutineExamples : MonoBehaviour
{int time = 0;// 啟動協程void Start(){StartCoroutine(MyTimerCoroutine()); // 更名為MyTimerCoroutineStartCoroutine(CreateManyCubesCoroutine()); // 更名為CreateManyCubesCoroutine}// 計時器協程IEnumerator MyTimerCoroutine(){while (true){print("秒" + time);time++;yield return new WaitForSeconds(1);}}// 生成大量立方體協程IEnumerator CreateManyCubesCoroutine(){for (int i = 0; i < 100000; i++){GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);obj.transform.position = new Vector3(Random.Range(-100, 100), Random.Range(-100, 100), Random.Range(-100, 100));if (i % 1000 == 0) // 每生成1000個立方體暫停一幀,避免卡頓{yield return null;}}}
}
總結
你可以簡化理解迭代器函數:C# 看到迭代器函數和 yield return
語法糖,就會把原本是一個的函數變成"幾部分"。我們可以通過迭代器從上到下遍歷這"幾部分"進行執行,就達到了將一個函數中的邏輯分時執行的目的。