多个FileStream用于在独立线程中同时读取/写入同一文件的不同部分

Dou*_*las 4 .net c# file-io multithreading

我有一个大磁盘文件(大约8 GB),包含我需要读取的几百万条记录,在内存中处理,并写回另一个文件.所有记录都具有固定长度(例如,100字节).

我正在考虑将我的进程并行化以在多个线程(通常是4-8)上运行,每个线程将(唯一地)分配要处理的文件的特定部分(例如,1 GB块).由于每个线程都会限制其读取和写入已分配的文件部分,因此我的代码不存在种族危险的风险.

我是否允许初始化多个线程,每个线程都有自己的线程,FileStream用于在不锁定的情况下读取/写入同一文件,而不会有损坏的风险?假设目标文件已提前扩展到其完整大小(使用FileStream.SetLength),并且FileShare在打开每个目标文件时指定了相应的标志FileStream.

另外,如果多个线程同时访问同一个文件,是否会因缓冲丢失而导致速度降低?我担心FileStream该类的MSDN文档中的"检测流位置更改"部分,其中指出:

FileStream对象的句柄没有独占保留时,另一个线程可以同时访问文件句柄并更改与文件句柄关联的操作系统文件指针的位置.[...]

如果在对Read方法的调用中检测到句柄位置的意外更改,.NET Framework将丢弃缓冲区的内容并再次从文件中读取流.这可能会影响性能,具体取决于文件的大小以及可能影响文件流位置的任何其他进程.

这适用于我的情况,还是由FileStream实例创建的文件句柄是独立且独立的,即使访问同一个文件?

usr*_*usr 6

这非常安全.

MSDN文章中没有提到问题的风险,因为它仅适用于您自己更改底层句柄的情况.你根本没有访问句柄.

您会注意到随机磁盘IO虽然会破坏性能.您可能希望通过从文件中读取大块(16MB左右)并使用锁来防止并发读写调用来缓解这种情况.请注意,即使在不同的FileStream实例上也需要防止并发调用,因为操作系统不会原子地处理IO.在内部,它们被分成小尺寸,以实现公平性和可预测的延迟.这导致随机IO.

为什么不创建一个读取器线程将缓冲区推入BlockingCollection?您可以在多个线程上使用Parallel.ForEach处理该集合.