快速阅读大量文件

8
我有很多(>100k)相对较小的文件(1kb - 300kb),需要读取和处理。我目前正在循环遍历所有文件,并使用File.ReadAllText读取内容,进行处理,然后读取下一个文件。这很慢,我想知道是否有一种好的优化方法。
我已经尝试使用多线程,但由于这似乎是IO绑定的,我没有看到任何改进。

1
哪一部分花费的时间最长?是加载文件还是处理它们? - Nick Larsen
@NickLarsen:正在加载文件。 - Tim
即使加载需要最长时间,多线程仍然可以带来收益,因为它至少可以从总运行时间中删除(大部分)处理方面。 - Reed Copsey
你们是在更新文件并将其写回,还是仅计算一些文件集的函数? - Ira Baxter
5个回答

8
您的想法很正确——读取这么多文件可能会限制您的潜在加速,因为磁盘I/O将成为限制因素。
话虽如此,您很可能可以通过将数据处理传递到单独的线程中来进行小幅改进。
我建议尝试使用一个单独的“生产者”线程来读取您的文件。该线程将受到IO限制。当它读取一个文件时,它可以将“处理”推入线程池线程(.NET 4任务也非常适用于此),以便进行处理,这将使其能够立即读取下一个文件。
这将至少将“处理时间”从总运行时间中剔除,使您的作业总时间几乎与磁盘IO一样快,前提是您有额外的一个或两个核心可供使用...

多个生产者向线程安全的数据结构写入会增加磁盘访问吞吐量吗?(好奇你为什么只建议一个生产者) - Minh Tran

2

我会将处理过程放到一个单独的线程中进行。我会读取文件并将数据存储在队列中,然后读取下一个文件。

在第二个线程中,让线程从队列中读取数据并进行处理。看看是否有帮助!


0

磁盘寻道时间可能是限制因素之一(这是进行Make时最常见的瓶颈之一,通常涉及大量小文件)。愚蠢的文件系统设计具有目录条目并坚持为文件指定磁盘块的指针,这保证了每个文件至少需要1次寻道。

如果您使用的是Windows,我建议切换到使用NTFS(它将小文件存储在目录条目中,从而每个文件可以节省一个磁盘寻道)。我们也使用磁盘压缩(更多计算但CPU便宜且快速,但磁盘空间较少-->读取时间较少);如果您的文件都很小,则可能与此无关。如果您使用的是Linux,则可能存在相应的文件系统等效物。

是的,您应该启动一堆线程来读取文件:

     forall filename in list:   fork( open filename, process file, close filename)

你可能需要对此进行节流以防止线程耗尽,但我建议你至少使用数百个线程而不是仅有2或3个。如果这样做,你就告诉操作系统可以在磁盘上读取很多位置,并且可以通过磁盘位置(电梯算法)对多个请求进行排序,这也有助于最小化磁头运动。


0
我建议使用“多线程”来解决这个问题。当我读到你的帖子回答时,突然发现Reed Copsey的答案会如此高效。你可以在link上找到由Elmue准备的此解决方案的示例。希望这对你有用,感谢Reed Copsey。 问候

0

我同意Reed和Icemanind的评论。此外,请考虑如何提高磁盘IO。例如,将文件分散到多个磁盘上,以便可以并行读取,并使用更快的磁盘,如固态硬盘或者RAM盘。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接