4

简而言之:

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

将多线程应用程序的亲和性设置为仅使用一个内核怎么样?

长篇:

我正在尝试在其自己的线程上运行 2D 引擎的物理特性。它工作正常,起初性能似乎正常,但我决定让游戏尝试以 10K FPS 和 120FPS 的物理速度运行,进入任务管理器并将亲和力设置为程序只能使用一个内核的位置。

在将亲和力设置为一个核心之前,FPS 大约为 1700,之后它达到了大约 70FPS。我没想到会出现这种下降。我告诉游戏尝试以 300 FPS 和 60 FPS 运行物理。

同样的事情发生了。

我没有多想,所以我只是继续修改引擎。后来我在更改了一些绘图代码后再次对其进行了测试,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();

    }

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

4

2 回答 2

8

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

将多线程应用程序的亲和性设置为仅使用一个内核怎么样?

在这两种情况下,答案都差不多。如果您的程序在单核上运行,则一次只运行一个线程。这意味着任何时候一个线程必须等待另一个线程,您都需要操作系统执行上下文切换,这是一项相当昂贵的操作。

当在多核上运行时,需要交互的两个线程很有可能同时运行,因此操作系统不需要执行上下文切换来让您的代码继续运行。

所以真的,需要大量线程间同步的代码在单核上运行速度会变慢。

但你可以让它变得更糟。自旋锁或任何类型的忙等待循环绝对会破坏性能。原因应该很明显。你一次只能运行一个线程,所以如果你需要一个线程来等待某个事件,你应该告诉操作系统让它立即进入睡眠状态,以便另一个线程可以运行。

相反,如果您只是执行一些“不满足条件,继续循环”繁忙循环,那么您将保持线程运行,即使它无关紧要。它会继续循环*直到操作系统决定它的时间到了,它会安排另一个线程。(如果线程没有被某些东西阻塞,它通常可以一次运行超过 10 毫秒。)

在一般的多线程编程中,特别是在单核上运行的多线程代码中,你需要表现得很好,而不是过多地占用 CPU 内核。如果您无事可做,请允许另一个线程运行。

猜猜你的代码在做什么。

你觉得这些线条的效果是什么?

   if (!(al_get_timer_count(timer) > prevCount))
        continue;

运行循环!我准备好跑步了吗?不?然后再次运行循环。我现在准备好跑步了吗?仍然没有?再次运行循环......

换句话说,“我现在拥有 CPU,我永远不会投降!如果其他人想要 CPU,他们将不得不从我冰冷的尸体上拿走它!”

如果你没有什么可以使用 CPU 的,那就放弃它,尤其是当你有另一个线程准备好运行时。

使用互斥锁或其他一些同步原语,或者如果您可以使用更近似的基于时间的睡眠周期,请调用Sleep().

但不要,如果你想要任何一种体面的性能,无限期地占用 CPU,如果你正在等待另一个线程进行一些处理。

于 2011-09-23T20:48:02.347 回答
1

当你看一个处理器时,不要把它看成一个只计算一个接一个的块。把它看成一个计算器,你必须预留时间

Windows(和所有操作系统)确保为所有正在运行的应用程序保留这段时间。当您运行一个程序时,计算机不仅会执行新程序想要执行的所有计算,Windows 还会为程序分配特定的时间。当那个时间结束时,下一个程序会有一些时间。windows 为您完成所有这些,因此只有在您想了解它时才有意义。

不过,这确实会影响您对多线程的看法,因为当 Windows 环顾四周并看到一个多线程应用程序时,它会说“我将把它作为 2 个单独的程序处理”,因此它会为两者分配时间。因此,一个人不会完全阻止另一个人进行计算。

所以不,多线程运行它不会降低程序的性能,但它会使周围的其他程序变慢一点。并产生少量开销。但是,如果您正在进行大量计算并且导致程序挂起,请随意使用多线程。

于 2011-09-23T18:54:46.010 回答