App/game 在协程运行时完全冻结
App/game freezes completely while coroutine runs
我的 Android ARCore Unity app/game 在协程运行时冻结,然后在协程完成后恢复。协程位于附加到游戏对象的脚本中,协程在 Start() 函数中调用。我已经尝试将 yield return null;
插入协程的更多部分,这减少了暂停时间,但增加了更多暂停,导致对象实例化后一两秒的游戏玩法非常不稳定(基本上不存在)。发生这种情况可能是因为 ARCore 不支持多线程渲染吗?如果是这种情况(或不是),我该如何解决这个问题,以便我的协程在实例化对象后运行(我猜 'in the background'),因此它不会影响游戏玩法 FPS?
这是我的代码:
void Start()
{
StartCoroutine(MyCoroutine());
}
IEnumerator MyCoroutine ()
{
yield return null;
Transform[] allChildren = GetComponentsInChildren<Transform>();
foreach (Transform child in allChildren)
{
if (child.gameObject.GetComponent<MeshFilter>())
{
if (!child.gameObject.GetComponent<MeshCollider>())
{
child.gameObject.AddComponent<MeshCollider>();
}
}
child.gameObject.tag = "CenterObject";
}
}
这是因为你在协程中陷入了循环。您需要将 yield 移动到循环内部:
IEnumerator MyCoroutine ()
{
Transform[] allChildren = GetComponentsInChildren<Transform>();
foreach (Transform child in allChildren)
{
if (child.gameObject.GetComponent<MeshFilter>())
{
if (!child.gameObject.GetComponent<MeshCollider>())
{
child.gameObject.AddComponent<MeshCollider>();
}
}
child.gameObject.tag = "CenterObject";
yield return null;
}
}
即便如此,如果这是您循环访问的大量子项,则可能只是性能问题。
协程在构造它们时似乎有开销,如下所述:https://forum.unity.com/threads/startcoroutine-performance-cost.233623/
鉴于您要实例化对象,我会建议这些路径:
- 将协程更改为简单的函数调用,因为您似乎不需要在循环迭代之间有任何延迟,这是在 Unity 中使用协程的主要想法。您还添加了碰撞器并期望游戏继续进行,如果您需要注册碰撞,这可能会导致意外行为。
- 如果可能,实例化预先连接了碰撞器的预制件。
- 使用对象池,您可以在游戏开始前创建对象并在需要时激活它们,并在销毁它们时禁用它们(如有必要)。
除了修复协程的答案外:
协程并不是真正的多线程!这就是为什么如果协程中有一个很长的任务,你的应用程序就会冻结。
协程的 yield return
使它 easy/lazy 可以做一个快速动画或类似的东西,因为协程有点 "remember" 他们离开的地方并从这一点继续(到用简单的话来说)所以你可以 运行 显然 "parallel" 很多事情。但它仍然在同一个线程中 运行s 所以实际上它似乎只是并行执行,因为一切都在两个帧之间执行。
如果您确实有一项耗时的任务想在另一个线程中完成,那么请查看 async await,这是自 Unity 2017 以来 Unity 真正的多线程。
然而 Unity 不是 线程保存意味着大多数 API 只能在主线程中使用...
我的 Android ARCore Unity app/game 在协程运行时冻结,然后在协程完成后恢复。协程位于附加到游戏对象的脚本中,协程在 Start() 函数中调用。我已经尝试将 yield return null;
插入协程的更多部分,这减少了暂停时间,但增加了更多暂停,导致对象实例化后一两秒的游戏玩法非常不稳定(基本上不存在)。发生这种情况可能是因为 ARCore 不支持多线程渲染吗?如果是这种情况(或不是),我该如何解决这个问题,以便我的协程在实例化对象后运行(我猜 'in the background'),因此它不会影响游戏玩法 FPS?
这是我的代码:
void Start()
{
StartCoroutine(MyCoroutine());
}
IEnumerator MyCoroutine ()
{
yield return null;
Transform[] allChildren = GetComponentsInChildren<Transform>();
foreach (Transform child in allChildren)
{
if (child.gameObject.GetComponent<MeshFilter>())
{
if (!child.gameObject.GetComponent<MeshCollider>())
{
child.gameObject.AddComponent<MeshCollider>();
}
}
child.gameObject.tag = "CenterObject";
}
}
这是因为你在协程中陷入了循环。您需要将 yield 移动到循环内部:
IEnumerator MyCoroutine ()
{
Transform[] allChildren = GetComponentsInChildren<Transform>();
foreach (Transform child in allChildren)
{
if (child.gameObject.GetComponent<MeshFilter>())
{
if (!child.gameObject.GetComponent<MeshCollider>())
{
child.gameObject.AddComponent<MeshCollider>();
}
}
child.gameObject.tag = "CenterObject";
yield return null;
}
}
即便如此,如果这是您循环访问的大量子项,则可能只是性能问题。
协程在构造它们时似乎有开销,如下所述:https://forum.unity.com/threads/startcoroutine-performance-cost.233623/
鉴于您要实例化对象,我会建议这些路径:
- 将协程更改为简单的函数调用,因为您似乎不需要在循环迭代之间有任何延迟,这是在 Unity 中使用协程的主要想法。您还添加了碰撞器并期望游戏继续进行,如果您需要注册碰撞,这可能会导致意外行为。
- 如果可能,实例化预先连接了碰撞器的预制件。
- 使用对象池,您可以在游戏开始前创建对象并在需要时激活它们,并在销毁它们时禁用它们(如有必要)。
除了修复协程的答案外:
协程并不是真正的多线程!这就是为什么如果协程中有一个很长的任务,你的应用程序就会冻结。
协程的 yield return
使它 easy/lazy 可以做一个快速动画或类似的东西,因为协程有点 "remember" 他们离开的地方并从这一点继续(到用简单的话来说)所以你可以 运行 显然 "parallel" 很多事情。但它仍然在同一个线程中 运行s 所以实际上它似乎只是并行执行,因为一切都在两个帧之间执行。
如果您确实有一项耗时的任务想在另一个线程中完成,那么请查看 async await,这是自 Unity 2017 以来 Unity 真正的多线程。
然而 Unity 不是 线程保存意味着大多数 API 只能在主线程中使用...