一、协程
协程是 Unity 内置的异步机制,通过 yield 暂停执行,实现任务在多帧中分段执行。与普通函数不同,协程可在执行过程中挂起和恢复,呈现"并发"效果,但本质上仍运行于主线程。若在协程中进行耗时操作,仍会导致主线程阻塞。因此,协程更适合处理异步事件的调度,而非需要多线程计算的任务。
优势:
- 使用简洁:在需要处理耗时的异步操作(如等待 HTTP 传输、资源加载、文件 I/O)时,官方建议优先考虑协程。
- Unity 生命周期集成:协程由
MonoBehaviour
管理,随脚本或对象生命周期自动中止。比如当GameObject
被停用或销毁时,其上运行的协程也会停止。 - 无需线程切换:协程运行在 Unity 主线程,不必担心线程安全,因为代码始终在主线程执行。
劣势:
- 依赖 MonoBehaviour
- 无法直接获取返回值:协程返回类型为
IEnumerator
,无法直接提供结果。通常需通过回调、全局状态或等待协程结束来获取数据,不如Task<T>
直接。 - 错误处理复杂:在协程内不能直接使用
try/catch
捕获包含yield
的代码块中的异常,这使得异常处理更加困难。未处理的异常可能导致游戏逻辑问题被掩盖。 - 性能与GC开销:尽管单个协程开销小,但大量协程会增加垃圾回收压力并可能影响帧率(如装箱迭代器、
WaitForSeconds
等对象),尤其是在每帧更新后统一调度时。
使用场景:
需要按照顺序执行、需要暂停、运行比单个帧花费时间更长的操作。
- 将对象移动到某个位置。
- 为对象提供要执行的任务列表。
- 淡入淡出视觉或音频。
- 等待资源加载:如
Resources.LoadAsync
/SceneManager.LoadSceneAsync
。 - 网络请求封装:先
UnityWebRequest.SendWebRequest()
,然后yield return request
等待请求完成,再检查结果。
yield return
Yield 表示该方法是一个迭代器,它将在多个帧上执行,而 return 与常规函数一样,在该点终止执行并将控制权传递回调用方法。
不同之处在于,对于协程,Unity 知道从上次中断的地方继续该方法。yield return 后面的内容将指定 Unity 在继续之前将等待多长时间。
yield return null
- 等待下一帧yield return new WaitForSeconds(秒数)
- 等待一段时间
对于重复延迟,可以创建一个对象优化性能。
WaitForSeconds delay = new WaitForSeconds(1); // 创建对象
Coroutine coroutine;
void Start()
{
StartCoroutine("MyCoroutine");
}
IEnumerator MyCoroutine()
{
int i = 100;
while (i > 0)
{
// Do something 100 times
i--;
yield return delay; // 使用对象
}
// All Done!
}
yield return new WaitForSecondsRealtime(秒数)
- 实时等待秒数yield return new WaitUntil(条件)/WaitWhile(条件)
- 等待委托
1. 用外部函数
yield return new WaitUntil(IsEmpty);
bool void IsEmpty()
{
...
//返回true或false
}
2. 用lambda表达式
IEnumerator CheckFuel()
{
yield return new WaitWhile(() => fuel > 0);
...
}
yield return new WaitForEndOfFrame()
- 等待帧结束
会等到 Unity 渲染完每个 Camera 和 UI 元素,然后再实际显示帧。这方面的典型用途是截取屏幕截图。yield return StartCoroutine()
- 等待另一个协程
void Start()
{
// 启动协程
StartCoroutine(MyCoroutine());
}
IEnumerator MyCoroutine()
{
// 启动等待第二个协程
yield return StartCoroutine(MyOtherCoroutine());
}
IEnumerator MyOtherCoroutine()
{
...
yield return new WaitForSeconds(1);
}
结束协程
yield break
- 在协程完成前结束协程StopCoroutine
- 在协程外部停止协程
bool stopCoroutine;
Coroutine runningCoroutine;
void Start()
{
runningCoroutine = StartCoroutine(MyCoroutine());
}
void Update()
{
if (stopCoroutine == true)
{
StopCoroutine(runningCoroutine);
stopCoroutine = false;
}
}
IEnumerator MyCoroutine()
{
// Coroutine stuff...
}
StopAllCoroutines()
- 停止MonoBehaviour上的所有协程
需要从启动它们的行为中调用 。
其他:
二、Async
待续。。。