使用 .NET ThreadPool 时 Fps 下降

Sen*_*gal 5 multithreading unity-game-engine threadpool

我之前曾问过这个问题,但没有提供代码,因为我没有简单的方法来做到这一点。然而现在我在 Unity 中启动了一个新项目,并尝试复制该行为,而不附加所有不必要的包袱。

这是我当前的设置:

public class Main : MonoBehaviour
{
    public GameObject calculatorPrefab;
    void Start ()
    {
        for (int i = 0; i < 10000; i++)
        {
            Instantiate(calculatorPrefab);
        }
    }
}

public class Calculator : MonoBehaviour
{
    void Start ()
    {
        ThreadPool.QueueUserWorkItem(DoCalculations);
    }

    void DoCalculations(object o)
    {
            // Just doing some pointless calculations so the thread actually has something to do.
            float result = 0;
            for (int i = 0; i < 1000; i++)
            {
                    // Note that the loop count doesn't seem to matter at all, other than taking longer.
                    for (int i2 = 0; i2 < 1000; i2++)
                    {
                            result = i * i2 * Mathf.Sqrt(i * i2 + 59);
                    }
            }
    }
}
Run Code Online (Sandbox Code Playgroud)

两个脚本都附加到游戏对象。“主”脚本位于场景中放置的游戏对象上,应该在启动时创建一堆其他游戏对象,然后依次为线程池排队一些随机计算。显然,这会在启动时产生相当大的 CPU 峰值,但这不是问题所在。问题是主线程似乎被这个阻塞了。换句话说,它会产生可怕的 fps。这是为什么 ?它不是应该在后台运行吗?这背后的全部意义不就是不要让主线程无响应吗?

我真的很难弄清楚我做错了什么,因为据我所知,没有比这更简单的了。

nVe*_*lia 0

在第一帧上,您实例化 10000 个预制件。对于单个框架来说这是相当大的负载。在第二帧上初始化 10000 个线程池。这是相当多的线程,我确信您会遇到一些前期初始化成本。

后台任务并不复杂。我使用后台任务来执行长时间运行的操作。例如网络调用和长时间运行的计算。我认为你的任务不太适合。换句话说,前期成本超过了运行计算的成本。

尝试使用协程来分解您的计算和实例化。我认为对于这个特定的后台任务来说这是一个更好的解决方案。

编辑根据下面的评论进行了一些测试。

  • 10k 实例化平均(中位数)花费 104 毫秒。编辑器的帧率很差,使用了我的 I7 CPU 容量的大约 15%。
  • 10k QueueUserWorkItem 平均(中位数)花费 23 毫秒。编辑器锁定了几秒钟。我的 CPU 容量达到了 99%。

结论 对工作线程进行排队会产生一些成本,但不会很多。问题主要在于您的实例化。那么,为什么我们要使用 1000 个工作线程来进行如此简单的计算呢?