如果我有一个彼此独立的固定数量的计算,多线程会显着提高性能吗?

时间:2014-08-18 18:54:20

标签: c++ multithreading performance sdl

我正在编写一个光线投射游戏引擎。 可以在不知道任何其他光线的情况下计算每条光线(我只计算距离)。 由于计算之间没有等待时间,我想知道是否值得努力使光线计算成为多线程。 是否可能会提升性能?

4 个答案:

答案 0 :(得分:10)

如果正确完成,很可能多线程会提高性能。您已经说明了问题的方式,它是多线程的理想选择,因为计算是独立的,可以将线程之间的协调需求降至最低。

仍然的某些原因可能无法加速,或者可能无法达到预期的全速:

1)瓶颈可能不是片上CPU执行资源(例如,ALU绑定操作),而是共享内存或共享LLC带宽等内容。

例如,在某些体系结构中,单个线程可能能够使内存带宽饱和,因此添加更多内核可能无济于事。更常见的情况是单个核心可以使一些分数饱和,1 / N <1。主存储器带宽为1,该值大于1 / C,其中C为核心计数。例如,在4核盒上,一个核心可能能够消耗50%的带宽。然后,对于内存限制计算,您将获得良好的扩展到2个核心(使用100%的带宽),但几乎没有高于此。

核心之间共享的其他资源包括磁盘和网络IO,GPU,窥探带宽等。如果您有超线程平台,此列表会增加,以包含共享相同内容的逻辑核心的所有级别的缓存和ALU资源物理核心。

2)争论&#34;在实践中&#34;在理论上和#34;之间的操作之间独立的。

您提到您的运营是独立的。通常这意味着它们逻辑独立 - 它们不共享任何数据(除了可能不可变的输入之外),并且它们可以写入单独的输出区域。但是,这并没有排除这种可能性,因为任何给定的实现实际上都会有一些隐藏的共享。

一个典型的例子是假共享 - 其中独立变量属于同一个缓存行,因此从不同线程对不同变量的逻辑独立写入最终会破坏核心之间的缓存线。

在实践中经常遇到的另一个例子是通过库进行争用 - 如果您的例程大量使用malloc,您可能会发现所有线程都花费大部分时间等待分配器内的锁定,因为malloc是共享资源。这可以通过减少对malloc的依赖(可能通过更少,更大的malloc)或使用良好的并发malloc(如hoard或tcmalloc)来解决。

3)跨线程分配和收集计算的实现可能会压倒您从多个线程获得的优势。例如,如果为每个单独的光线启动一个新线程,则线程创建开销将主导您的运行时,您可能会看到负面的好处。即使您使用持久线程的线程池,也要选择一个&#34;工作单元&#34;太细粒度会带来很多协调开销,这可能会消除你的好处。

同样,如果必须将输入数据复制到工作线程或从工作线程复制输入数据,您可能看不到预期的缩放。在可能的情况下,使用pass-by-reference获取只读数据。

4)你没有超过1个核心,或者你有超过1个核心,但它们已经被占用运行其他线程或进程。在这些情况下,协调多个线程的工作是纯粹的开销。

答案 1 :(得分:2)

可能是的,多线程(例如pthreads)可以提高性能;但你肯定想要进行基准测试(如果你的程序受内存限制而不是CPU限制,你可能会感到失望)。你也可以考虑OpenCL(在GPGPU上运行一些常规数值计算)和OpenMP(通过编译指示明确要求编译器并行化你的一些代码) )。 可能会认为Open-MPI可以在多个通信进程上运行。如果你勇敢(或疯狂),你可以混合几种方法。

实际上,它取决于算法和系统(硬件和操作系统),您应该进行基准测试(例如,与您的需求相关的一些微型原型)。

如果在某个特定系统上,瓶颈是内存带宽(而不是CPU),多线程或多处理不会有太大帮助(并且可能降低性能)。 此外,同步的成本可能差别很大(例如,在某些系统上锁定mutex可能会非常快,而在其他系统上则会慢50倍。)

答案 2 :(得分:2)

一般来说,取决于。鉴于计算是独立的,听起来这是由于线程导致潜在性能改进的良好候选者。雷计算通常可以从中受益。

但是,还有许多其他因素,例如内存访问要求,以及运行它的底层系统,这将对此产生巨大影响。如果没有正确编写,多线程版本的运行速度通常比单线程版本慢,因此分析是明确回答这个问题的唯一方法。

答案 3 :(得分:1)

非常可能。独立计算是并行化的理想选择。在光线投射的情况下,它们中有很多它们可以在硬件允许的平行线程中很好地传播。

计算的意外瓶颈本来可以提供完美的数据独立性,可以是对附近位置的并发写入(虚假共享的缓存行)。