2013-02-05 38 views
1

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

我测试了代码,它似乎更快,但经过第二次思考,我不知道为什么。将大文件分割成n个输入文件(你可以'前进'到同一个文件中以达到同样的效果,最少的预处理),然后让每个进程只需调用iostream :: readLine就可以了它自己的块? (因为iostream也读入它自己的缓冲区)。在多线程之间共享单个缓冲区似乎没有任何固有的优势,因为工作人员实际上并不在相同的数据线上运行。另外,没有什么好方法我不认为要并行化,以便它们在同一行上工作。我只是想了解我看到的性能增益,并知道它是'flukey'还是跨平台可扩展/可重复的...

+1

除顺序文件读取之外的任何其他操作都会造成更多的伤害,尤其是对于需要实际的机械磁盘操作来“真正”读取不在磁盘/驱动器缓存中的数据的大型文件。我不太确定你的单个循环缓冲区设计。单个文本行的线程间通信不会很有效 - 太多的原子操作和读取线程在解析行时应该填充缓冲区。我可能会带着一个更大的缓冲区实例池。 –

回答

0

当您I/O受限时,您可以通过使用两个线程,一个读取文件,第二个处理。这样,阅读将永远不会等待处理(期待最后一行),并且您将阅读100%。

缓冲区应该足够大,足以让消费者一次完成足够的工作,这通常意味着它应该包含多行(我推荐至少4000个字符,但可能更多)。这将防止线程上下文切换成本不切实际地高。

单线程:

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

双螺纹:

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

在某些平台上,你可以得到同样的加速也无绪,利用交叠I/O,但使用线程可能会更清晰。

只要您真的是I/O绑定,使用多个消费者线程将不会带来好处。

+0

我也发现这个以及..但不iostream有它自己的缓冲区?为什么这是加速? – user2044555

+0

单线程工作时,需要处理缓冲区,然后才读取下一个缓冲区。如果某些读取X需要新的数据,则需要等到读取完整的新缓冲区为止。该流没有执行“推测性预读”。在执行线程时,处理与读取下一个缓冲区并行完成。 – Suma

0

在你的情况下,你的程序至少有两个资源竞争CPU和硬盘。在单线程方法中,您请求数据,然后等待一个空闲的CPU让HD传输它。然后,您处理数据,而HD空闲。这很糟糕,因为两个资源中的一个始终空闲。如果您有多个CPU或多个HD,则此更改一点。而且,在一些情况下,存储器带宽(即RAM连接)也是限制资源。

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