Unity基础-协程
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
语法糖,就会把原本是一个的函数变成"几部分"。我们可以通过迭代器从上到下遍历这"几部分"进行执行,就达到了将一个函数中的逻辑分时执行的目的。