【发布时间】:2012-06-23 12:04:51
【问题描述】:
我有一个大磁盘文件(大约 8 GB),其中包含我需要读取、在内存中处理和写回另一个文件的数百万条记录。所有记录的长度都是固定的(比如 100 字节)。
我正在考虑将我的进程并行化以在多个线程(通常为 4-8 个)上运行,每个线程将(专门)分配文件的特定部分以进行处理(例如,1 GB 块)。由于每个线程都会将其读取和写入限制在分配给它的文件部分,因此我的代码不存在竞争风险。
我是否允许初始化多个线程,每个线程都有自己的FileStream,以便在没有锁定的情况下读取/写入同一个文件,而不会有损坏的风险?假设目标文件已经提前展开到完整大小(使用FileStream.SetLength),并且在打开每个FileStream 时都指定了适当的FileShare 标志。
另外,如果多个线程同时访问同一个文件,我是否会冒着因缓冲丢失而导致减速的风险?我担心FileStream class 上的 MSDN 文档中的“检测流位置变化”部分,其中指出:
当
FileStream对象的句柄没有独占保留时,另一个线程可以同时访问文件句柄并更改与文件句柄关联的操作系统文件指针的位置。 […]如果在调用
Read方法时检测到句柄位置发生意外更改,.NET Framework 将丢弃缓冲区的内容并再次从文件中读取流。这可能会影响性能,具体取决于文件的大小以及可能影响文件流位置的任何其他进程。
这是否适用于我的情况,或者FileStream 实例创建的文件句柄是否不同且独立,即使访问同一个文件?
【问题讨论】:
-
写入目标文件时是否需要保留记录的顺序?
-
如果文件大小未知,你会怎么做文件分区?您的情况可能是您(大致)知道文件大小,我问如果文件大小是随机的怎么办?
-
@stt106:我不久前写了这个问题。现在,在大多数情况下,我可能会选择动态调度——例如,我会用占位符填充文件中所有 100MB 块的并发队列,然后让每个线程尽快从队列中选择下一个块完成。如果你的进程是 I/O-bound,你应该瞄准大块来促进顺序磁盘访问。类似于 OpenMP 的“引导式”调度策略的东西可能会在最后提供顺序访问和负载平衡之间的最佳折衷。
标签: c# .net multithreading file-io