在Unity中,我应该在什么时候使用协程,而不是在Update()中减去Time.deltaTime



下面是我想强调的差异的一个简单示例。

使用协同程序:

public float repeatRate = 5f;
void Start()
{
StartCoroutine("RepeatSomething");
}
IEnumerator RepeatSomething()
{
while (true)
{
yield return new WaitForSeconds(repeatRate);
// Do something
}
}

使用Update()Time.deltaTime:

public float repeatRate = 5f;
private float timer = 0;
void Update()
{
if (timer < 0)
{
// Do something
timer = repeatRate;
}
timer -= Time.deltaTime;
}

我应该在什么时候使用一种而不是另一种,每种的优点/缺点是什么?

在大多数情况下,答案是.

一般来说,Update和Coroutine之间的性能差异并不相关。只要遵循最适合你的方法,但如果你想遵循类似科罗廷的方法,请使用性能更高的MEC Coroutines而不是Unity Coroutine

  • MEC Coroutine性能分析
  • CCD_ 6性能分析

简单使用

正如团结论坛中所提到的,"Coroutines对于在多个帧上执行方法很有用[然后忘记它]。">

如果你计划只使用其中的几个(小于10k?),那么你也可以使用Unity Coroutines

高级使用

目前Unity支持Task/Async,但性能仍然很低。因此,您可能会考虑使用Coroutines来模拟Async的功能。

在这种情况下,您甚至可以使用Coroutines来删除所有(或大部分)Update循环,例如您发布的示例。

这在性能方面非常有用,尤其是在您的特定情况下,因为当您使用Update循环时,即使您什么都不做,您也会不断地检查if (timer < 0)。即使是空的更新循环仍然是一个性能问题。

另一方面,当事件发生时,您可能只是启动和停止Coroutines。当Coroutine停止时,性能成本变为0。

如果你想遵循这种方法,我强烈建议使用MEC协程,它可以消除Unity协程引起的所有性能问题(并且具有相同的功能)。


结论

  1. 在大多数情况下,这种性能差异并不相关
  2. MEC Coroutines比Update循环的性能高一点
  3. Update循环通常比Unity Coroutines更具性能
  4. Unity Coroutines应仅用于很少发生的简单定时任务

PS:这个关于统一协同程序的答案可能有助于你深入了解它们是如何工作的
PPS:这个老答案可能会让你有更深入的了解,但它有点过时了,尤其是当它谈到垃圾收集时。

我只是想在这里发布,我最近尝试了MEC协同程序,如果我们检查延迟和响应时间,它比Unity协同程序更具性能,但只有当你运行这么多(比如至少超过10K的简单程序)时,这才是重要的,很可能你永远不会或应该这样做。然而,GC与Unity协同程序的工作从那以后就被修复了,实际上MEC协同程序现在给GC的工作要多得多,大约是10倍!所以我用协程增加了一个数字,给一个新的协程增加一个增量,就像开发者在2016年做的性能测试一样,Unity的协程保持了播放模式,但在我的情况下产生了68MB的垃圾,而MEC的则产生了0,73GB的垃圾。。。。所以我把我的郊游改回了Unity。

简单的答案是使用可读性更强的(据我所知,性能没有明显差异)。我(通常)会使用Coroutines,因为这将有助于保持您的更新循环更有组织性,而且我觉得它们通常更容易设置(您不需要为计时器等创建变量)

老实说,他们将执行相同的任务。它们都将执行每一帧(在您的情况下,检查自初始执行以来是否已经过了5秒)。然而,有一些关键差异。也就是说,最重要的是执行顺序。Coroutines始终Update()之后运行。如果出于某种原因,Update()中发生了一些需要刷新的事情,以便用正确的信息更新Coroutine,那么这一点很重要。但通常情况下,情况并非如此。

总之,任何一个都会完成你想要的任务,而这通常归结为偏好和组织问题。

永远不要使用Coroutines

这将大大改进解决问题的方式,尤其是在游戏引擎中,并避免不必要的垃圾创建、垃圾收集和缓慢调用以及其他与接口和协同程序有关的问题。

这也意味着你的编程更快、更简单,更容易思考和推理什么在做什么、在哪里、何时、为什么和如何做。

科罗丁是一种令人上瘾的药物,应该避免,好像它们没有任何好处一样。因为他们对你的程序没有更好的思考和编写的好处。

一旦你开始使用协同出游,就有点像在咖啡里放奶油和糖。当它们在某种程度上结合在一起时,你总是会添加更多的内容,这一切似乎都在增强效果

你最终甚至会在咖啡质量上妥协,因为它的味道似乎不再那么重要了。你已经对奶制品、糖和咖啡上瘾了,而不仅仅是咖啡因

你会开始喝得太多,因为现在你已经掌握了配方,喝得太容易了。它尝起来很对,不会错的。但你会坐立不安,压力大,睡不好,身体上会出现一些奇怪的脂肪,你会在你最爱的人中易怒

看似解决方案的东西变成了问题。然后,真正的大问题开始出现,在你的健康和心理健康方面

所有这些都可以通过简单地喝绿茶和从不参加户外活动来避免。因为你以后为了成为一个咖啡迷而付出的代价根本不值得

永远

对于每一个收益,您实际上都在创建一个新对象,正如您所说的new WaitForSeconds()。然而,这种差异仍然没有那么显著。另一方面,协程可读性更强,尤其是考虑到需要在不同等待时间的同一个协程中使用多个yield的情况,在Update中实现这样的东西会使代码变得非常混乱。

最新更新