多个线程从同一个文件中读取

Posted

技术标签:

【中文标题】多个线程从同一个文件中读取【英文标题】:Multiple Threads reading from the same file 【发布时间】:2011-04-01 10:19:13 【问题描述】:

我有一个需要多次读取的 xml 文件。我正在尝试使用 Parallel.ForEach 来加快这个过程,因为读入的数据都与读入的顺序无关。数据只是用于填充对象。我的问题是即使我每次都在线程中以只读方式打开文件,但它抱怨它已被另一个程序打开。 (我没有在文本编辑器或任何东西中打开它:))

如何从同一个文件中完成多次读取?

编辑:该文件大约 18KB 非常小。它被阅读了大约 1,800 次。

谢谢

【问题讨论】:

您的硬盘仍然只有一个磁头,因此您一次只能读取一次。您期望从中获得哪些性能改进? 文件是否适合磁盘缓存?如果是这样,那么多次读取将很快,否则如果文件足够小以适合内存,则使用内存映射文件代替并从中读取。否则,硬盘将花费大量时间抖动而不是执行顺序读取,并且您将失去性能而不是获得它。 硬盘上的一个头?我敢肯定,如今即使是单个盘片驱动器也有多个磁头以及缓存等,可以解决磁头特定的减速问题。 @GrayWizardx:错过重点的方法:) @Timwi 猜我做到了。哪一点?我提供了一个替代解决方案来解决多次读取问题。严格指定 FileShare.Read 会修复错误但不会解决问题。 【参考方案1】:

打开文件时需要指定FileShare.Read

using (var stream = new FileStream("theFile.xml", FileMode.Open, FileAccess.Read, FileShare.Read))

    ...

这样文件可以多次打开阅读

【讨论】:

虽然这是正确的,但除非发布者将文件分成块,否则任何真正的加速都将使用多线程实现是值得怀疑的。 @Mitch Wheat:确实如此。但我只是在回答 OP 的问题,而不是判断使用多线程是否是个好主意;)【参考方案2】:

根据文件的大小和您正在执行的读取类型,首先将文件加载到内存中,然后直接向您的线程提供对其的访问可能会更快。

您没有提供有关文件、读取等的任何细节,所以我不能确定它是否能满足您的特定需求。

一般前提是在单个线程中加载文件一次,然后直接(通过 Xml 结构)或间接(通过 XmlNodes 等)为每个线程提供对文件的访问。我设想类似于:

    加载文件 对于每个 Xpath 查询,将匹配的节点分派给您的线程。

如果线程不直接修改 XML,这可能是一个可行的替代方案。

【讨论】:

【参考方案3】:

如果要多个线程从同一个文件中读取,需要指定FileShare.Read

using (var stream = File.Open("theFile.xml", FileMode.Open, FileAccess.Read, FileShare.Read))

    ...

但是,由于多种原因,您不会因此获得任何加速:

    您的硬盘一次只能读取一件事。尽管您有多个线程同时运行,但这些线程最终都会相互等待。 您无法轻松解析 XML 文件的一部分。您通常每次都必须解析整个 XML 文件。由于您有多个线程一直在读取它,因此您似乎并不期望文件会更改。如果是这样,那你为什么需要多次阅读呢?

【讨论】:

+1 对于“1”和“2”cmets。当多个线程试图读取同一个文件时,FileAccess.Read 和 FileShare.Read 将无法解决问题。所以正如“2”注释中提到的,如果我们只需要阅读它,那么我们可以先阅读一次,然后给多个线程“做处理”。 关于第1点,这不适用于磁盘阵列之类的东西,对于服务器软件来说,这是很容易预料到的。【参考方案4】:

虽然是一篇旧帖子,但它似乎很受欢迎,所以我想我会添加一个解决方案,该解决方案在需要读取文件的多线程环境中效果很好。但是,该文件必须足够小以至少在您的处理期间可以保存在内存中,并且该文件只能在共享访问期间读取而不是写入。

string FileName = "TextFile.txt";
string[] FileContents = File.ReadAllLines(FileName);

foreach (string strOneLine in FileContents)

  // Do work on each line of the file here

只要文件只是被读取,多个线程或程序就可以同时访问和处理它,而不会互相影响。

【讨论】:

以上是关于多个线程从同一个文件中读取的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中,如何使用多个线程读取一个文件?

如何避免从 LINQ to Entities 中的多个线程从 SQL 数据库中读取相同的记录

从多个线程读取数组时要注意啥?

允许多个线程一次读取给定条件变量,但只有一个线程写入

如何使用多个线程读取大量文件,请帮助我!

JMeter接口测试——参数化(从文件中读取参数)