如何为多个文件处理选择最佳I / O策略?

时间:2017-06-26 09:46:09

标签: c++ multithreading asynchronous filesystems

让我们假设我们有下一个任务(非常抽象):

我们有一个文件夹,要处理各种文件(文件数可能是1,2或几千)。每个文件只能按顺序处理(这意味着无法读取内存中的整个文件并在多个线程中处理它)。文件处理的结果应该是生成新文件,也是顺序写入的。如何使用所有可用的CPU内核进行操作?

我只看到两种方法:

  1. 使用由多个线程处理的任务队列。每个任务正在处理单个文件,例如从文件读取块,处理块,将块写入结果文件。

  2. 使用像Pipeline图案之类的东西。我们有一个输入线程,它以异步方式读取文件并将块发布到多个处理队列。每个线程读取自己的队列并进行块处理。然后将结果发布到输出队列。输出线程写入结果文件。所以我们有1个输入读取线程,1个输出写入线程和几个进程线程。

  3. 块处理操作不是很快,读取速度慢。

    操作系统:Mac / Linux,也许是Windows。

    哪种方法更好?我们还有其他解决方案吗?

3 个答案:

答案 0 :(得分:1)

可能最简单有效的解决方案是使用单个读取器线程,低于默认优先级。如果有一个免费的CPU核心,它就会运行。这将创建一个工作线程(处理一个输入文件并将其写回)。由于这些线程以默认优先级运行,因此这将自我平衡。当所有CPU忙于处理文件时,读取器线程将不会获得太多的CPU时间,因此不会生成大量新的工作线程。

分离文件处理并将文件写回磁盘是没有意义的;这只会产生许多不成文的工作在内存中排队的可能性。

答案 1 :(得分:1)

最好的方法是编写一个简单的Task类,它可以独立完成整个操作(读取,处理,写入),因此与外部的线程不安全操作没有任何联系。然后使用任务队列,其中固定数量的线程可以获取这些任务并处理它们。大量线程通常是核心* 2.

可以在数学上证明,选项2总是等于或慢于基于任务的解决方案,并且在所有情况下它都会更复杂。选项2更可行的唯一情况是线程切换成为实际的瓶颈。 I.E.如果你的服务器有1000个并发但有状态的连接而只有一个网卡,那么有1个网络线程可以为1000个处理线程提供服务,而不是在通过线路发送的每个字节上唤醒1000个线程。 / p>

基于任务的解决方案还可以更轻松地衡量吞吐量并比较其他线程对其的影响,因为您可以简单地在任务/秒内进行测量。

答案 2 :(得分:0)

这两种方法都有一些优点和缺点。

单读者

  1. pro:从处理中提供良好的学术抽象层读者,并可能最终形成一个更好的编程模型。
  2. pro:另外,假设您可以为所有其他线程提供作业(如果游行速度明显慢于读取操作)并且文件系统没有碎片化,那么您可以更好地利用系统。
  3. con:#2很难实现,所以很可能这种优势不会存在。
  4. con:编程起来比较困难,你需要顶部的fifo或其他队列和同步。
  5. 处理线程中的读取:

    1. pro:易于实施,无需队列或同步
    2. pro:在碎片文件系统中更好地工作:可以通过操作系统或硬件优化多个io请求以减少延迟。此外,延迟较低的请求将更快启动处理,无论是在单个阅读器中,无论如何都必须等待。
    3. pro:读取操作本身有一个非系统部分,它也可以在一个线程中运行,并且是并行处理的一部分。
    4. con:可能会在非碎片系统中松动,因为它会增加一些类似碎片的行为。
    5. BTW,有更多可能的处理方案。您忘记提及的是拥有一个编写器线程,您的处理转储将导致队列,并让后台进程编写它。这可能会给你额外的提升。每个线程都不需要等待写入。

      您也可以使用在一个队列中写入的并行读取器,而不是从该队列处理的内容(更复杂的编程:-)但在某些情况下有效。

      好吧,并行作家也可以工作。

      此外,您可以在不同的本地磁盘(不是目录,而是物理磁盘)之间分发文件。如果并行完成,这肯定会提高您的读/写性能。