当前位置: 首页 > news >正文

Unity协程Coroutine与UniTask对比

原理对比

CoroutineUniTask
本质IEnumerator 的协作调度器async/await 状态机(IAsyncStateMachine)
调度方式Unity 内部调用 MoveNext()自建 PlayerLoopRunner 控制状态推进
内存管理引用类型,频繁分配 GC结构体 UniTask,低 GC 压力
多线程支持主线程限制可结合多线程(但默认仍在主线程)
工具组合能力强(如 WhenAll, WithCancellation)

调用方式

协程

1.不使用StartCoroutine调用时,可通过编译,但是无法启动,协程进不去

2.使用StartCoroutine可正确执行协程逻辑,正常执行等待,对当前函数体无要求

3.可使用yield return等待协程执行完毕,需要当前函数体有IEnumerator关键字标识

4.可使用await关键字等待协程执行完毕,需要当前函数体有async关键字标识

示例代码如下

void CorTest()
{Test();Debug.Log("Coroutine 3");StartCoroutine(Test());Debug.Log("Coroutine 4");
}IEnumerator Test()
{Debug.Log("Coroutine 1");yield return new WaitForSeconds(1.1f);Debug.Log("Coroutine 2");
}

当调用CorTest后,输出结果为

可以看到,先输出了"Coroutine 3",而没有输出"Coroutine 1",表示没有使用StartCoroutine启动时,协程是进不去的。使用了StartCoroutine后,"Coroutine 2"在"Coroutine 1"及"Coroutine 4"一秒后输出。await关键字情况同下面UniTask调用

UniTask

1.UniTask无论是否使用await关键字,都可以正确进入逻辑,正常执行等待,对当前函数体无要求

2.可使用await等待UniTask执行完毕,需要当前函数体有async关键字标识

示例代码如下

async void TaskTest()
{Test2();Debug.Log("UniTask 3");await Test2();Debug.Log("UniTask 4");
}async UniTask Test2()
{Debug.Log("UniTask 1");await UniTask.Delay(1100);Debug.Log("UniTask 2");
}

当调用TaskTest后,输出结果为

可以看到,两次调用Test2均正常进入,且正常执行了等待逻辑,两次"UniTask 2"输出均在"UniTask 1"后,而"UniTask 4"输出也是在"UniTask 2"后执行的。函数体如果没有async关键字时,内部是无法使用await的,编译不通过。

性能测试

yield return null  VS UniTask.Yield()

测试代码

public int times = 1000;void CorProTest()
{StartCoroutine(CorProEnum());
}IEnumerator CorProEnum()
{for (int i = 0; i < times; i++){yield return null;}
}void UniTaskProTest()
{UniTaskProTask();
}async UniTask UniTaskProTask()
{for (int i = 0; i < times; i++){await UniTask.Yield();}
}

由于无法抓取一段时间内的纯Profiler数据,所以只取一帧的数据,每帧数据都是一致的。

可以看到,两个对GC都没有影响,因为协程本身并没有新建对象,所以不存在分配内存。可以理解成等价的。

 yield return new WaitForSeconds VS UniTask.Delay

测试代码

public int times = 1000;void CorProTest()
{StartCoroutine(CorProEnum());
}IEnumerator CorProEnum()
{for (int i = 0; i < times; i++){yield return new WaitForSeconds(0.01f);}
}void UniTaskProTest()
{UniTaskProTask();
}async UniTask UniTaskProTask()
{for (int i = 0; i < times; i++){await UniTask.Delay(10);}
}

同上,抓取某一帧的数据

 可以看到,调用yield return new WaitForSeconds(0.01f)时,有20B的内存分配,这是因为创建了引用对象WaitForSeconds,所以必定会有内存分配。调用await UniTask.Delay(10)没有内存分配,是因为UniTask内部使用的是结构体,而不是类。

yield return new WaitUntil VS UniTask.WaitUntil

测试代码

public int times = 1000;void CorProTest()
{StartCoroutine(CorProEnum());
}IEnumerator CorProEnum()
{bool value = true;for (int i = 0; i < times; i++){yield return new WaitUntil(() => value);}
}void UniTaskProTest()
{UniTaskProTask();
}async UniTask UniTaskProTask()
{bool value = true;for (int i = 0; i < times; i++){await UniTask.WaitUntil(() => value);}
}

同上,抓取某一帧数据

可以看到 ,调用yield return new WaitUntil时,有24B的内存分配,这是因为创建了引用对象WaitUntil,所以必定会有内存分配。调用await UniTask.WaitUntil没有内存分配,是因为UniTask内部使用的是结构体,而不是类。

总结

        测试了这三种常用的用法,可以看到,协程除了null没有GC产生(因为没有创建对象)外,其他两种用户均产生了GC,只是量比较小,而UniTask三种用法都没有GC产生。

        如果只考虑GC方面的差异,在项目使用过程中,如果量比较大,使用比较频繁,建议使用UniTask。而对于一般用量来讲,差距可以忽略不计。而GC是可以使用对象池来优化的,可以一定程度上降低GC的分配。对象池参考另一篇博客从CPU缓存出发对引用池进行优化。

        然而,最终选择使用哪一种,需要结合其他情况考虑,协程使用起来比较方便,而UniTask也有一些比较好的功能,比如UniTask支持带返回值的异步,封装了多任务同时进行、等待以及其他功能。

http://www.lqws.cn/news/161857.html

相关文章:

  • 如何排查和解决PHP连接数据库MYSQL失败写锁的问题
  • 数据结构:递归:泰勒展开式(Taylor Series Expansion)
  • SAP学习笔记 - 开发24 - 前端Fiori开发 Filtering(过滤器),Sorting and Grouping(排序和分组)
  • Docker MCP 目录和工具包简介:使用 MCP 为 AI 代理提供支持的简单安全方法
  • 阿里云服务器安装nginx并配置前端资源路径(前后端部署到一台服务器并成功访问)
  • Spring Boot 使用 SLF4J 实现控制台输出与分类日志文件管理
  • uv管理spaCy语言模型
  • 使用Hutool工具进行rsa加密解密示例:
  • JVM垃圾回收器-ZGC
  • GC1809:高性能音频接收与转换芯片
  • NineData云原生智能数据管理平台新功能发布|2025年5月版
  • SpringCloud——Nacos
  • SDC命令详解:使用set_fanout_load命令进行约束
  • 可穿戴设备:健康监测的未来之眼
  • clickhouse常用语句汇总——持续更新中
  • 牛客小白月赛113
  • Git的由来与应用详解:从Linux内核到现代开发的革命性工具
  • windows server2019 不成功的部署docker经历
  • [特殊字符] 一文了解目前主流的 Cursor AI 免费续杯工具!
  • AI时代的弯道超车之第二十四章:AI伦理和版权问题
  • 智慧园区数字孪生全链交付方案:降本增效30%,多案例实践驱动全周期交付
  • STM32入门教程——OLED调试工具
  • Elasticsearch最新入门教程
  • vue3 eslint ts 关闭多单词命名检查
  • AirSim/Cosys-AirSim 游戏开发(二)使用自定义场景
  • 大模型学习
  • adb 连不上真机设备问题汇总
  • uniapp微信小程序视频实时流+pc端预览方案
  • 音视频之视频压缩编码的基本原理
  • Rust Floem UI 框架使用简介