卡帧协程书写时的性能优化及方法

卡帧协程书写时的性能优化及方法

什么是协程?什么是协程?

unity协程是一个可以挂起协程执行的函数,挂起后立即返回主函数,执行主函数的剩余部分,从下一个开始继续执行协程剩余的函数中断指令的行,直到中断指令完成。函数体全部执行完毕,协程结束。

由于中断指令的出现,可以将一个函数分成多个帧执行。

性能:

在性能上不会比普通函数更多的开销

协程的好处:

让原本用异步+回调方法编写的非人为代码像素游戏素材,可以写成看似同步的方式。

能够逐步完成一项耗时的任务。如果需要大量计算,可以在协程中处理计算,随着时间的推移进行,可以分散计算压力

协程的缺点:

unity 多次执行协程_unity 协程 异常_unity 协程 异常

协程本质上是迭代器,基于统一的生命周期。大量打开的协程会导致gc

如果同时激活了多个协程,可能会出现多个高开销协程挤进同一个帧造成的卡帧。

编写协程时的性能优化:

常见的问题是直接new一条中断指令,带来不必要的GC负担。您可以重用全局中断指令对象来优化开销;在 Yielders.cs 文件中,上面已经集中创建了静态类型的对象

分析这个链接

协程在哪里执行?

协程不是线程,不会异步执行;协程和monobehaviour的更新函数一样,也是在主线程中执行的

Unity每帧都会处理对象上的协程,也就是说协程和update一样,是Unity每帧都会处理的函数

经过测试,协程在lateUpdate之后至少每帧运行一次。

unity 协程 异常_unity 多次执行协程_unity 协程 异常

参考unity的生命周期图

unity 协程 异常_unity 协程 异常_unity 多次执行协程

协程如何结束?

方法一:StopCoroutine(string methodName);

方法二:stopAllCoroutines 挂起当前脚本下的所有协程

方法三:gameObject.active = false 可以停止对象上所有协程的执行。即使再次激活,也无法继续执行。但是注意 MonoBehaviour enabled = false 不能停止协程;相比updateunity 协程 异常,MonoBehaviour enabled = false时可以停止

原因:由于在注册StartCoroutine时协程是在GameObject上注册的,它的生命周期受GameObject的生命周期的限制,所以受GameObject是否活跃的影响。

结论:虽然协程是在MonoBehvaviour(StartCoroutine)中启动的,但协程函数的状态与MonoBehaviour完全处于同一水平,不受MonoBehaviour状态的影响。

协程结束的标志是什么?

unity 协程 异常_unity 协程 异常_unity 多次执行协程

如果最后一个 yield return IEnumerator 已经迭代到最后一个,MoveNext 将返回 false。此时,Unity 将从 cortoutines 列表中删除 IEnumerator。

只有当这个对象的MoveNext()返回false,即IEnumertator的Current已经迭代到最后一个元素时,才会执行yield return之后的语句。

中断函数类型:

在下一帧的所有 Update() 调用之后执行 null

WaitForSeconds() 等待指定的秒数,并在此帧(延迟后的帧)上调用所有 update() 函数后执行。即等待一段时间,受Time.timeScale影响unity 协程 异常音乐,当Time.timeScale = 0f时,yield return new WaitForSecond(x)将不满足。

WaitForFixedUpdate 等待固定帧,即等待物理周期结束执行

WaitForEndOfFrame 等待帧结束,即等待渲染周期结束执行

StartCoroutine 等待新的协程暂停

WWW等待加载完成,等待www的网络请求完成,isDone=true后执行

unity 协程 异常_unity 协程 异常_unity 多次执行协程

协程的执行顺序:

启动协程->执行协程->遇到中断指令时中断协程->返回上层函数继续执行上层函数的下一行代码->中断指令后结束,继续执行中断指令后的代码->协调进程结束

协程可以嵌套协程吗?

是的,yield return StartCoroutine是,执行顺序是:

子协程中断后返回父协程,父协程挂起,返回父协程的父函数。

决定父协程结束的标志是子协程是否结束。子协程结束后返回父协程执行后续代码。

同一个脚本实例可以同时运行多少个协程?

MonoBehaviour 提供的主线程中只能有一个正在运行的协程。因为协程不是线程,所以它们不是并行的。同时,一个脚本实例中可以有多个挂起的协程,但只有一个正在运行的协程

协程和线程有什么区别?

unity 协程 异常_unity 协程 异常_unity 多次执行协程

线程使用多核来实现真正的并行计算。缺点是会出现大量的锁、切换、等待问题。协程是非抢占式的,用户需要释放切换到其他协程的权利。因此,同时实际上只有一个协程有运行权,相当于单线程的能力。

协程是 C# 线程的替代方案,是 Unity 不使用线程的解决方案。

使用协程不考虑同步和锁

多个协程可以同时运行,它们会根据各自的启动顺序进行更新

其他说明:

1、IEnumerator 类型的方法不能带 ref 或 out 参数,但可以带传递的引用

2、函数Update和FixedUpdate中不能使用yield语句,否则会报错,但是可以启动协程

3、协程中,StartCoroutine()和yield return StartCoroutine()是不一样的。

前者只是启动一个新的 Coroutine,它与现有的 Coroutine 并行执行。

后者是返回一个新的Coroutine,也就是一条中断指令。新的协程执行时,会继承已有协程的执行。