我有一个大的磁盘文件(大约8GB),其中包含我需要读取、在内存中处理和写回另一个文件的数百万条记录。所有记录都是固定长度的(例如,100个字节)。
我正在考虑并行化我的进程以在多个线程(通常为4-8)上运行,每个线程都将(独占)分配给文件的一个特定部分来处理(例如,1 GB块)。由于每个线程都会限制其对已分配文件的部分的读和写,因此我的代码不存在发生种族冲突的风险。
是否允许我初始化多个线程(每个线程都有自己的FileStream ),以便在没有锁定的情况下读取/写入同一个文件,而不会导致损坏?假设目标文件已提前展开到其全部大小(使用FileStream.SetLength),并且在打开每个FileStream时指定了适当的FileShare标志。
此外,如果多个线程同时访问同一个文件,我是否会因为缓冲区的丢失而导致缓慢下降?我对FileStream class上的MSDN文档中的“检测流位置更改”部分表示关切,该部分指出:
当
FileStream对象对其句柄没有独占权时,另一个线程可以并发访问文件句柄,并更改与文件句柄关联的操作系统文件指针的位置。…
如果在对Read方法的调用中检测到句柄位置的意外更改,则.NET框架将丢弃缓冲区的内容并再次从文件中读取流。这可能会影响性能,这取决于文件的大小以及可能影响文件流位置的任何其他进程。
这是否适用于我的情况,或者FileStream实例创建的文件句柄是否是独立且独立的,即使访问同一个文件也是如此?
发布于 2012-06-23 12:25:04
这绝对安全。
MSDN文章中提到的问题没有风险,因为只有当您自己对底层句柄进行更改时,它才适用。您根本没有访问句柄。
不过,您会注意到随机磁盘IO会破坏性能。您可能希望通过从文件中读取大块(大约16 by )并使用锁来防止并发的读和写调用来减轻这一问题。请注意,即使在不同的FileStream实例上,您也需要防止并发调用,因为OS没有对IOs进行原子化处理。在内部,它们被分割成小尺寸,以保证公平性和可预测的延迟。这会导致随机IO。
为什么不创建一个阅读器线程将缓冲区推到BlockingCollection中呢?您可以在多个线程上使用Parallel.ForEach处理该集合。
发布于 2012-06-23 12:15:52
“内存映射文件将文件的内容映射到应用程序的逻辑地址空间。内存映射文件使程序员能够处理非常大的文件,因为内存可以并发管理,并且允许对文件进行完全、随机的访问,而不需要查找。内存映射的文件也可以跨多个进程共享。
CreateFromFile方法从指定的路径或磁盘上现有文件的FileStream创建内存映射文件。文件未映射时,更改将自动传播到磁盘。
CreateNew方法创建未映射到磁盘上现有文件的内存映射文件;并且适合为进程间通信(IPC)创建共享内存。
内存映射文件与名称相关联。
您可以创建内存映射文件的多个视图,包括文件部分的视图。您可以将文件的同一部分映射到多个地址以创建并发内存。要使两个视图保持并发状态,必须从同一个内存映射文件中创建它们。创建具有两个视图的同一个文件的两个文件映射并不提供并发性。“
http://msdn.microsoft.com/en-us/library/system.io.memorymappedfiles.memorymappedfile.aspx
https://stackoverflow.com/questions/11169354
复制相似问题