是否可以使用线程来加速文件读取?

时间:2010-06-16 14:55:00

标签: c++ multithreading file operating-system filesystems

我想尽快读取文件(40k行)[编辑:其余的已经过时]。

编辑:Andres Jaan Tack建议基于每个文件一个线程的解决方案,我想确定我得到了这个(因此这是最快的方式):

  • 每个条目文件一个帖子将其整个读取并将其内容存储在相关的容器中( - >与条目文件一样多的容器)
  • 一个线程计算输入线程读取的每个单元格的线性组合,并将结果存储在退出容器中(与输出文件关联)。
  • 一个线程按块(每4kB数据,大约10行)写入输出容器的内容。

我是否应该推断出我不能使用m-mapped文件(因为程序在待机状态下等待数据)?

先谢谢。

此致

mystère先生。

6 个答案:

答案 0 :(得分:26)

当你进一步询问时,你的问题会更深入一些。我会尝试涵盖你所有的选择......

读取一个文件:多少个线程?

使用一个主题。

如果您直接从单个线程直接读取文件,操作系统将无法像您所想的那样以小块的形式获取文件。相反,它将以巨大的(指数级增长的)块预取文件,因此你几乎不会为进入磁盘而付出代价。您可能会等待磁盘几次,但一般情况下,文件已经在内存中,这甚至与mmap无关。

操作系统非常擅长这种顺序文件读取,因为它是可预测的。当您从多个线程中读取文件时,您实际上是在随机读取 ,这显然是不可预测的。使用随机读取,预取器往往效率低得多,在这种情况下可能使整个应用程序变慢而不是更快。

注意:甚至在您添加设置线程及其余所有线程的成本之前。这也花费了一些成本,但与更多阻塞磁盘访问的成本相比,它基本上没什么用。

读取多个文件:有多少个线程?

使用与文件一样多的线程(或一些合理的数字)。

为每个打开的文件单独完成文件预取。一旦开始阅读多个文件,您应该并行读取其中的几个文件。这是有效的,因为磁盘I/O Scheduler将试图找出读取所有磁盘的最快顺序。通常,操作系统和硬盘驱动器本身都有磁盘调度程序。同时,预取者仍然可以完成其工作。

并行读取多个文件总是更好比逐个读取文件。如果你确实一次读过一个,你的磁盘就会在预取之间闲置;这是将更多数据读入内存的宝贵时间!唯一可能出错的方法是,如果你的RAM太少而无法支持许多打开的文件;那不常见了。

请注意:如果您对多个文件读取过于过分,那么读取一个文件将开始将其他文件从内存中踢出来,然后您将回到随机读取状态。

n 文件合并为一个。

处理和生成多个线程的输出可能有效,但这取决于您需要如何组合它们。在任何情况下,你都必须要小心你如何同步线程,尽管肯定有一些相对简单的无锁方法可以做到这一点。

有一件事要寻找:不要费心在小(< 4K)块中写文件。在致电write()之前,一次收集至少4K的数据。此外,由于内核会在您编写文件时锁定该文件,因此请勿同时从所有线程中调用write();他们都会互相等待而不是处理更多的数据。

答案 1 :(得分:18)

[编辑:原始问题是否启动最多40,000个线程会加快文件读取速度]

由于创建线程和上下文切换的开销,您建议最有可能减慢访问速度。更多线程只有在您

时才有用

1)计算限制,你有额外的核心,可以帮助工作

2)阻塞和其他线程在等待其他人解除阻塞时可以正常工作

3)你有一个非常聪明的算法,利用缓存行为

最有可能的是你的速度受磁盘和/或内存带宽的限制而不是计算限制,因此单个执行线程可以最大化这些速度。

答案 2 :(得分:4)

是的,这是浪费时间。在最好的情况下,你最终会得到大致相同的性能。在最坏的情况下,它可能会损害磁盘寻找文件不同部分的性能,而不是连续读取它。

答案 3 :(得分:4)

与其他读者相比,我认为理论上可能会有一些好处,即使您在SP(单处理器)系统上运行也是如此。 但是,我永远不会这样做多达40K行(假设你谈论正常大小的行)。

他们的关键是Amardeep的答案,他/她说当线程因某种原因被阻止时创建线程很有用。

现在,映射文件如何“工作”? 当您第一次访问该区域中的内存页时 - 处理器会生成页面错误。操作系统将文件内容(这涉及磁盘访问)加载到内存页面中。然后执行返回到你的线程。

我也相信页面错误操作系统会填充一堆连续的页面,而不仅仅是单个页面。

现在,重要的是,在页面错误处理期间,您的线程暂停。此外,在此期间不会加载CPU(除了其他进程可能执行的操作)。

因此,如果您查看时间刻度,您会看到两个部分的时间段:一个是CPU加载的(这里是您读取页面内容并进行一些处理),另一个是CPU几乎空闲且I执行磁盘上的/ O.

另一方面,您可以创建多个线程,每个线程被分配用于读取文件的不同部分。您可以从两个效果中受益:

  1. 当其中一个被I / O阻止时,其他线程有机会加载CPU(或多个CPU,如果MP系统)。

  2. 即使处理时间非常短(因此CPU不是瓶颈) - 仍然有一个好处。这与以下事实有关:如果您在同一物理设备上发出多个I / O,它就有机会更有效地执行它们。

  3. 例如,当从HD驱动器读取许多不同的扇区时,您实际上可以在一个磁盘旋转中读取它们。

    P.S。

    当然,我从未想过要为40K线路做这件事。创建线程,等待它们完成,上下文切换,逻辑顺应,错误/失败处理等的开销。

    我会尝试为至少几十MB的文件执行此操作。

答案 4 :(得分:1)

这是粒度问题。你有一个小文件,而且处理的工作很少。一个线程可能在一个时间片中吞噬整个文件并在下一个时间片中处理它。两个线程会比一个更差。在将并行性作为性能解决方案之前,您需要一个更大的任务。

答案 5 :(得分:-1)

我在想这个。

你有8个核心,所以制作8个线程。让每个线程解析文件的一个块。因此,您需要获取设备/磁盘块大小。当线程解析了一个块时,让线程解析一个尚未“分配”给线程的新线程。

我的另一个想法是拥有2个主题。解析线程和线程只是跨过文件的磁盘块,即只读取每个块的第一个字节,从而迫使文件尽可能快地读入内存。

但是,这可以成为一场比赛。没有什么比真正的现场直播!人们会告诉你! :)找到合适的价格!