Unity插件之UniTask
在我们介绍UniTask之前,先来复习一下协程。
异步加载的演变
核心前置知识点
- 同步代码:一行执行完才走下一行,会卡主线程
- 异步代码:不阻塞主线程,等待 IO / 延时 / 网络时主线程继续渲染(玩家可移动)
异步加载的演变
- Unity传统异步方案:协程
Coroutine (IEnumerator) - C#原生异步:
async/await + Task - 第三方优化方案:
UniTask
协程
1 | IEnumerator TestCoroutine() |
Task(async/await)
1 | async Task<int> GetResultAsync() |
异步方法的返回类型通常是Task或Task<T>,其中Task表示异步操作,Task<T>表示异步操作完成后返回一个类型为T的结果。
在异步操作中,可能会遇到需要取消任务的情况,例如用户取消操作或超时。C#提供了CancellationToken来支持任务的取消机制。通过传递取消令牌,提高程序的灵活性和响应性。
创建取消令牌:
1 | public async Task MainAsync() |
UniTask
UniTask 是专为Unity引擎打造的高性能、零GC异步编程库。
GC是什么?我们先来回顾一下GC的概念。
GC(Garbage Collection),顾名思义,他是垃圾回收的意思。
我们都知道,内存分为两块:栈、堆。
- 栈内存:速度极快、空间小、自动分配自动释放。
- 存:int、float、bool、结构体(struct)、局部变量。
- 用完立刻自己消失,完全不用 GC 管。
- 堆内存:空间大、速度慢、需要人管理。
- 存:所有
class类对象、new 出来的东西、字符串、数组、集合。
- 存:所有
GC在垃圾回收的时候做了三件事:
- 标记:遍历所有内存,标记哪些对象还在被使用,哪些已经废弃。
- 清除:把废弃的垃圾对象直接删掉,释放内存。
- 整理(压缩):把零散空闲内存拼在一起,避免内存碎片。
当堆内存不够用了或者达到系统阈值时,就会触发GC。
但是现在有一个关键问题:GC工作时,会短暂暂停游戏主线程,表现就是:瞬间卡顿、掉帧。而协程的一大痛点在于:每次yield return null或者返回别的什么,都要经历一次装箱,也就是把值类型装成引用类型的object,这样会频繁触发GC,导致卡顿。
而UniTask基于值(struct)设计,零GC,解决Unity异步开发的核心痛点。
使用UniTask在 Window - Package Manager - 左上角+号 - Add package from git URL - 输入UniTask的Git地址:
1 | https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask |
下载UniTask导入项目:
- 需要引用命名空间
1 | using Cysharp.Threading.Tasks; |
- UniTask
1 | async UniTask TestUniTask() |
除了这种标准用法外,我们还需要注意如果想在一个不是异步的方法中使用异步方法,我们需要用到.Forget()
例如,当我们加载一个场景时,可能会这样写:
1 | private void Start() |
其中,LoadStartScene()是一个异步方法,.Forget()表示不等待它执行完。
正常来说可以这样写:
1 | await LoadStartScene(); |
但在 Unity 的Start() 不是 async 方法,不能直接写 await。所以用了 .Forget()。









