需要多少线程才能使它们成为糟糕的选择?

Tom*_*Tom 12 c++ performance multithreading boost

我必须使用boost :: thread在C++中编写一个不那么大的程序.

手头的问题是处理大量(可能是数千或数万.数百和毫秒也是可能的)多个(可能)大文件.每个文件都独立于另一个文件,它们都位于同一目录中.我想使用多线程aproach,但问题是,我应该使用多少线程?我的意思是,数量级是多少?10,500,12400?

存在一些同步问题,每个线程应返回一个值结构(为每个文件累积),并将这些结构添加到"全局"结构中以获取整体数据.我意识到一些线程可能因为同步而"饿了",但如果它只是一个添加操作,那有关系吗?

我在想

for(each file f in directory){

    if (N < max_threads)//N is a static variable controlling amount of threads
         thread_process(f)
    else
       sleep()
}
Run Code Online (Sandbox Code Playgroud)

这是在HP-UX中,但我无法经常测试它,因为它是一个远程且非常难以访问的服务器.

Kir*_*sky 13

根据Herb Sutter在他的文章中讨论的Amdahl定律:

一些程序的处理完全是"O(N)"并行化(称为p部分),只有那部分可以直接在具有越来越多处理器核心的机器上扩展.该程序的其余工作是"O(1)"顺序.[1,2]假设完全使用所有可用内核而没有并行化开销,Amdahl定律表示在具有N个内核的机器上实现该程序工作负载的最佳加速由下式给出:
公式图像

在您的情况下,I/O操作可能需要大部分时间,以及同步问题.您可以计算阻塞(?)慢速I/O操作所花费的时间,并大致找到适合您任务的线程数.


可以在此处找到Herb Sutter的并发相关文章的完整列表.

  • 问题是这假设其他线程没有开销.这几乎不是这种情况,我会说每个核心有超过1个线程并不是真正有效(只要该线程始终处于负载状态).(继续...) (2认同)
  • 如果你的核心空闲了一段时间(例如等待输入的线程),那么将该核心添加另一个线程可能是值得的.此外,核心运行的线程越多,它就越需要移动缓存导致缓存未命中,这将真正减慢它的速度.虽然这是一个很好的"法律"(我认为它不能用科学标准来称呼它),但它并没有在现实世界中占据优势. (2认同)
  • 在这种特殊情况下,您还可以使用硬盘访问权限,这将是您真正的限制因素.我建议您有一个专门用于将文件读入内存的线程,然后将其交给其他线程进行处理,否则,如果您尝试从单独的线程上读取文件,则硬盘将开始跳转到整个地方.这将大大降低硬盘的读取速度,从而导致更长的处理时间.(在后面的视线中我可能应该发布这个作为答案,但是哦,好吧,没有代表我). (2认同)

Dav*_*kle 11

我对HP/UX不太了解,但在Windows世界中,我们使用线程池来解决这类问题.Raymond Chen 一段时间后写了这个,事实上......

如果线程数超过系统中CPU核心数的2倍,我通常不会期望在CPU绑定负载上能够很好地扩展任何东西.对于I/O绑定负载,您可能能够获得更多,具体取决于您的磁盘子系统的速度,但是一旦达到大约100左右,我会认真考虑更改模型......

  • 太多的线程也会破坏你的IO.磁盘头抖动和缓冲区争用将克服运行大量进程的好处.我会坚持使用经过试验和测试的"cpu cores*2"公式. (4认同)

pga*_*ast 6

详细说明它真的取决于

IO boundedness of the problem
    how big are the files
    how contiguous are the files
    in what order must they be processed
    can you determine the disk placement
how much concurrency you can get in the "global structure insert"
    can you "silo" the data structure with a consolidation wrapper
the actual CPU cost of the "global structure insert" 
Run Code Online (Sandbox Code Playgroud)

例如,如果您的文件驻留在3 TB的闪存阵列上,那么解决方案与它们驻留在单个磁盘上的方式不同(如果"全局结构插入"占用的数量少于读取的问题,那么I/O就会受到影响同样有一个带2个螺纹的2级管道 - 读取阶段为插入阶段供电.)

但在这两种情况下,架构可能都是2级的垂直管道.n读取线程和m写入线程,其中n和m由该阶段的"自然并发"确定.

为每个文件创建一个线程可能会导致磁盘抖动.就像你将CPU绑定进程的线程数量定制为自然可实现的CPU并发(并且高于创建上下文切换开销AKA颠簸)在I/O端也是如此 - 从某种意义上说,你可以想到磁盘颠簸为"磁盘上的上下文切换".


Mik*_*vey 6

你说文件都在一个目录中.这是否意味着他们都在一个物理驱动器上?

如果是这样,并假设它们尚未缓存,那么您的工作将是保持单个读头忙,并且没有多少线程可以帮助它.实际上,如果由于并行性而必须在轨道之间跳转,则可以减慢速度.

另一方面,如果计算部分花费大量时间,导致读头必须等待,那么有> 1个线程可能是有意义的.

通常,使用线程来提高性能是没有意义的,除非它允许您同时使并行的硬件工作.

更常见的是,线程的价值在于,例如,跟踪多个同时进行的对话,例如,如果您有多个用户,每个线程可以等待自己的Johny或Suzy而不会感到困惑.


Sin*_*ion 5

如果工作负载在I/O边界附近听起来很接近,那么您可能会获得最大吞吐量,其中包含与您拥有的主轴数相同的线程数.如果您有多个磁盘且所有数据都在同一个RAID 0上,则可能不需要任何多个线程.如果有多个线程试图访问磁盘的非连续部分,操作系统必须停止读取一个文件,即使它可能是头部的正下方,并移动到磁盘的另一部分服务的另一个线程,使它没有饿死.只有一个线程,磁盘需要永远不会停止读取以移动磁头.

显然,这取决于访问模式是非常线性的(例如视频重新编码)和数据实际上是在磁盘上未分段,这取决于很多.如果工作负载更多的是CPU限制,那么它就没那么重要了,你可以使用更多的线程,因为无论如何磁盘都会翻转它的拇指.

正如其他海报所示,首先介绍!