解决方法
有些原因你仍然可能无法加速,或者可能无法达到预期的全速,可能包括:
1)瓶颈可能不是片上cpu执行资源(例如,ALU绑定操作),而是像存储器或共享LLC带宽那样共享的东西.
例如,在某些体系结构上,单个线程可能能够使内存带宽饱和,因此添加更多内核可能无济于事.更常见的情况是单个核心可以使一些分数饱和,1 / N <1.主存储器带宽为1,该值大于1 / C,其中C为核心计数.例如,在4核盒上,一个核心可能能够消耗50%的带宽.然后,对于内存限制计算,您将获得良好的扩展到2个内核(使用100%的带宽),但几乎没有. 核心之间共享的其他资源包括磁盘和网络IO,GPU,窥探带宽等.如果您有超线程平台,则此列表会增加,以包括共享相同物理核心的逻辑核心的所有级别的缓存和ALU资源. 2)在“理论上”独立的操作之间“在实践中”的争用. 你提到你的操作是独立的.通常这意味着它们在逻辑上是独立的 – 它们不共享任何数据(除了可能不可变的输入之外)并且它们可以写入单独的输出区域.然而,这并不排除这种可能性,因为任何给定的实现实际上都有一些隐藏的共享. 一个典型的例子是错误共享 – 其中独立变量属于同一缓存行,因此从不同线程对不同变量的逻辑独立写入最终会破坏核心之间的缓存线. 在实践中经常遇到的另一个例子是通过库进行争用 – 如果你的例程大量使用malloc,你可能会发现所有线程都花费大部分时间等待分配器内的锁定,因为malloc是共享资源.这可以通过减少对malloc的依赖(可能通过更少,更大的malloc)或使用良好的并发malloc(如hoard或tcmalloc)来解决. 3)跨线程分配和收集计算的实现可能会压倒你从多个线程获得的优势.例如,如果为每个单独的光线启动一个新线程,则线程创建开销将主导您的运行时,您可能会看到负面的好处.即使您使用持久线程的线程池,选择太细粒度的“工作单元”也会产生大量协调开销,这可能会消除您的好处. 同样,如果必须将输入数据复制到工作线程和从工作线程复制,您可能看不到预期的缩放.在可能的情况下,对只读数据使用pass-by-reference. 4)你没有超过1个核心,或者你有超过1个核心,但它们已经被占用运行其他线程或进程.在这些情况下,协调多个线程的工作是纯粹的开销.