multithreading - 通过设置亲和性在单核上运行多线程程序的性能?

标签 multithreading mutex physics-engine affinity allegro5

简而言之:

在什么情况下在单核上运行多线程应用程序会破坏性能?

将多线程应用程序的关联设置为仅使用一个核心怎么样?

长:

我试图在它自己的线程上运行 2D 引擎的物理。它有效,起初性能似乎正常,但我决定让游戏尝试以 10K FPS 运行,物理以 120FPS 运行,进入任务管理器并将关联设置为程序只能使用一个核心的位置。

在将亲和性设置为一个核心之前,FPS 为 ~1700,之后变为 ~70FPS。没想到会有这么大的下降。我告诉游戏尝试以 300 FPS 和 60FPS 的物理速度运行。

同样的事情发生了。

我没有多想,就继续修改引擎。后来我改了一些绘图代码后再次测试,物理300 FPS,60FPS。所有内核都允许它管理 300FPS 就好了,与单核 FPS 的亲和力下降到 4。现在我知道在单核上运行多线程应用程序不可能那么糟糕,或者我不知道什么时候会发生您将亲和力设置为单个核心。

这是关于渲染/物理如何运行......

循环开始

收集输入直到 (1.0/FPS) 过去。

调用更新。

锁定物理线程互斥锁,因为游戏中的内容将使用物理数据,并且在此更新调用中的所有内容完成之前,我不希望引擎更新任何内容。

更新游戏中可能将 Draw 函数对象(保存要绘制的内容、绘制的位置、如何绘制)发送到渲染队列的所有内容。

解锁互斥锁。

渲染器对每个函数对象调用 operator() 并将它们从队列中删除。

更新画面。

重复循环。

物理线程循环:

    ALLEGRO_TIMER* timer(al_create_timer(1.0f / 60.0f));
    double prevCount(0);

    al_start_timer(timer);
    while(true)
    {
        auto_mutex lock(m_mutex);

        if(m_shutdown)
            break;
        if (!m_allowedToStep)
            continue;
                    // Don't run too fast. This isn't final, just simple test code.
        if (!(al_get_timer_count(timer) > prevCount))
            continue;

        prevCount = al_get_timer_count(timer);

        m_world->Step(1.0f / 60.0f, 10, 10); 
        m_world->ClearForces();

    }

//注意:Auto mutex 只是我创建的一个非常简单的对象,用于在构造函数中锁定互斥锁并在析构函数中解锁它。我正在使用 Allegro 5 的线程功能。

最佳答案

Under what scenarios can running a multithreaded app on a single core destroy performance?

What about setting the affinity of a multithreaded app to only use one core?


在这两种情况下,答案大致相同。如果您的程序在单核上运行,则一次仅运行一个线程。这意味着任何时候一个线程必须等待另一个线程,您都需要操作系统执行上下文切换,这是一项相当昂贵的操作。
当在多个内核上运行时,需要交互的两个线程很有可能同时运行,因此操作系统不需要为您的代码执行上下文切换。
所以真的,需要大量线程间同步的代码在单核上运行速度会变慢。
但是你可以让它变得更糟。
自旋锁或任何类型的忙等待循环绝对会破坏性能。原因应该很明显。您一次只能运行一个线程,因此如果您需要一个线程等待某个事件,您应该告诉操作系统立即将其置于 sleep 状态,以便另一个线程可以运行。
相反,如果您只是执行一些“while 条件不满足,继续循环”的忙循环,那么即使线程无关紧要,您也会保持线程运行。它会继续循环*直到操作系统决定它的时间到了,并调度另一个线程。 (如果线程没有被某些东西阻塞,它通常可以一次运行超过 10 毫秒。)
在一般的多线程编程中,*特别是在单核上运行的多线程代码,你需要玩得很好,不要过度占用 CPU 内核。如果您无事可做,请允许另一个线程运行。
并猜测您的代码在做什么。
你认为这些线条的作用是什么?
   if (!(al_get_timer_count(timer) > prevCount))
        continue;
运行循环!
我准备好运行了吗?不?然后再次运行循环。我现在准备好运行了吗?仍然没有?再次运行循环......
换句话说,“我现在拥有 CPU,我永远不会屈服!如果有人想要 CPU,他们将不得不从我冰冷的尸体上拿走它!”
如果你没有什么可使用CPU的,那就放弃吧,特别是如果您有另一个准备运行的线程。
使用互斥锁或其他一些同步原语,或者如果您可以使用更近似的基于时间的 sleep 周期,请调用 Sleep() .
但是,如果您想要任何体面的性能,请无限期地占用 CPU,如果您正在等待另一个线程进行一些处理。

关于multithreading - 通过设置亲和性在单核上运行多线程程序的性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7533415/

相关文章:

c# - Farseer物理质量/重量问题

.net - 是什么提供了自旋锁的有效性?

node.js - 网络 worker 线程 : is it OK to use "require" inside worker?

c - 让我确保我理解 C pthread 互斥体

互斥锁中的条件变量错误

javascript - Famo.us 多边形碰撞支持

c++ - cpp 主体线程的局部函数是否安全?如果是这样,从中调用静态函数呢?

Java - 静态 block 和线程同步问题 - 一个案例

c++ - 释放在不同同步上下文中使用的类成员

javascript - 如何使用 PhysicsJS 旋转固定物体?