1

我有一个很容易并行化的简单任务。基本上,相同的操作必须在一个(大的,几个 Gb)输入文件的每一行上重复执行。虽然我已经制作了一个多线程版本,但我注意到我的 I/O 是瓶颈。我决定构建一个实用程序类,其中包含一个“文件读取器”线程,该线程简单地直接向前读取并尽可能快地读取到循环缓冲区中。然后,多个消费者可以调用这个类并获得他们的“下一行”。给定 n 个线程,每个线程 i 的起始行是文件中的第 i 行,并且通过添加 n 找到该线程的每个后续行。事实证明,这不需要锁,几个关键的原子操作足以保留不变量。

我已经测试了代码,它似乎更快,但再想一想,我不知道为什么。将大文件分成 n 个输入文件不是一样快吗(您可以提前“搜索”到同一个文件中以实现相同的目的,最少的预处理),然后让每个进程简单地调用 iostream::readLine on它自己的块?(因为 iostream 也会读入它自己的缓冲区)。在多个线程之间共享单个缓冲区似乎没有任何固有的优势,因为工作人员实际上并不是在同一行数据上操作。另外,我认为没有什么好的方法可以并行化,这样它们就可以在同一条线上工作。我只想了解我所看到的性能提升,并知道它是“flukey”还是跨平台可扩展/可重现......

4

2 回答 2

0

在您的情况下,您的程序至少要竞争两种资源,即 CPU 和硬盘。在单线程方法中,您请求数据,然后使用空闲 CPU 等待 HD 传送数据。然后,您在 HD 空闲时处理数据。这很糟糕,因为这两种资源中的一种总是空闲的。如果您有多个 CPU 或多个 HD,这会有所改变。此外,在某些情况下,内存带宽(即 RAM 连接)也是一种限制资源。

现在,您的解决方案是正确的,您使用一个线程来保持 HD 忙碌。如果此线程阻塞等待 HD,则操作系统只是切换到处理某些数据的不同线程。如果它没有任何数据,它会等待一些。这样,CPU 和 HD 将至少在某些时候并行工作,从而提高整体吞吐量。请注意,您不能通过两个以上的线程来增加吞吐量,除非您还有多个 CPU,并且 CPU 是限制因素而不是 HD。如果你也写回一些数据,你可以通过第三个线程写入第二个硬盘来提高性能。否则,您不会从更多线程中获得任何优势。

于 2013-02-06T22:18:33.717 回答
0

当您受到 I/O 限制时,您可以通过使用两个线程来获得良好的加速,一个读取文件,第二个进行处理。这样,读数将永远不会等待处理(期待最后一行),您将进行 100% 的读数。

缓冲区应该足够大,以便一次性为消费者线程提供足够的工作,这通常意味着它应该由多行组成(我建议至少 4000 个字符,但可能更多)。这将防止线程上下文切换成本过高。

单线程:

  • 阅读 1
  • 过程1
  • 阅读 2
  • 过程2
  • 阅读 3
  • 过程 3

双螺纹:

  • 阅读 1
  • 进程 1/读取 2
  • 进程 2/读取 3
  • 过程 3

在某些平台上,使用重叠 I/O 也可以在没有线程的情况下获得相同的加速,但使用线程通常会更清晰。

只要您确实受 I/O 限制,使用多个消费者线程将不会带来任何好处。

于 2013-02-05T20:25:08.070 回答