我有一个易于并行化的简单任务。基本上,必须在(大的,几个Gb)输入文件的每一行上重复执行相同的操作。虽然我已经制作了多线程版本,但我注意到我的I / O是瓶颈。我决定构建一个包含单个“文件读取器”线程的实用程序类,该线程可以直接读取并尽可能快地读取到循环缓冲区中。然后,多个消费者可以打电话给这个班级并获得他们的“下一行”。给定n个线程,每个线程i的起始行是文件中的第i行,并且通过添加n找到该线程的每个后续行。事实证明,这不需要锁,一些关键的原子操作足以保留不变量。
我已经测试了代码并且看起来更快,但是第二个想法,我不确定为什么。将大文件分成n个输入文件并不是那么快(你可以'寻找'进入同一个文件以实现同样的事情,最少的预处理),然后让每个进程简单地调用iostream :: readLine on它自己的块? (因为iostream也会读入自己的缓冲区)。在多个线程之间共享单个缓冲区似乎没有任何固有的优势,因为工作者实际上并没有在相同的数据行上运行。另外,没有什么好办法我不想并行化,以便它们可以在同一条线上工作。我只想了解我所看到的性能提升,并了解它是否是“flukey”或跨平台可扩展/可重现......
答案 0 :(得分:0)
当您受I / O限制时,您可以通过使用两个线程获得良好的加速,一个读取文件,第二个执行处理。通过这种方式,读取将永远不会等待处理(期望最后一行)并且您将以100%的速度阅读。
缓冲区应该足够大,以便一次性为消费者线程提供足够的工作,这通常意味着它应该包含多行(我建议至少4000个字符,但可能更多)。这将防止线程上下文切换成本不切实际。
单线程:
双线程:
在某些平台上,使用重叠I / O也可以在没有线程的情况下获得相同的加速,但使用线程通常可以更清晰。
只要您确实受到I / O限制,使用多个消费者线程就不会带来任何好处。
答案 1 :(得分:0)
在您的情况下,您的程序至少有两种资源,即CPU和硬盘。在单线程方法中,您需要数据然后等待空闲CPU以便HD传送它。然后,您处理数据,而HD处于空闲状态。这很糟糕,因为两个资源中的一个总是处于空闲状态。如果您有多个CPU或多个HD,这会稍微改变一下。此外,在某些情况下,存储器带宽(即RAM连接)也是限制资源。
现在,您的解决方案是正确的,您使用一个线程来保持HD忙碌。如果此线程阻塞等待HD,则OS只会切换到处理某些数据的其他线程。如果它没有任何数据,它将等待一些。这样,CPU和HD将并行工作,至少在某些时候,可以提高整体吞吐量。请注意,除非您还有多个CPU且CPU是限制因素而不是HD,否则不能使用两个以上的线程来增加吞吐量。如果您正在写回一些数据,则可以使用写入第二个硬盘的第三个线程来提高性能。否则,你不会从更多线程中获得任何好处。