2009-08-20 116 views
2

我需要从3.7 GB文件读取小数据序列。我需要读取的位置是不是相邻的,但我可以对IO进行排序,以便从头到尾读取文件。如何利用磁盘IO排队

该文件存储在应能够处理/优化排队IO的iSCSI SAN上。

问题是,如何一次性完成我需要的所有数据/职位的一次性请求?可能吗?我不认为异步IO是一种选择,因为阅读是非常小的(20-200字节)

目前的代码如下所示:

using (var fileStream = new FileStream(dataStorePath, FileMode.Open, FileAccess.Read, FileShare.Read)) 
{ 
    for (int i = 0; i < internalIds.Count();i++) 
    { 
     fileStream.Position = seekPositions[i].SeekPosition; 
     ... = Serializer.DeserializeWithLengthPrefix<...>(fileStream, PrefixStyle.Base128); 

    } 
    ... 
} 

我在寻找各种方法来改善这个我/ O,因为我的表现有所降低。移动头部的所有寻求时间似乎都在增加。

回答

1

您是否在此上运行Performance Monitor(来自Microsoft Sysinternals)?

我不确定是什么问题,但我会猜测。如果您正在从SAN读取数据,我会认为磁盘访问会导致网络请求下的问题。第一次读取发送一个请求,读取和缓冲数据,然后串行器构造这些对象。在发送第二个请求时,SAN磁盘继续旋转,因此您必须等待数据旋转到位。

你试过多线程吗?如果您按顺序设置需要处理的文件部分的队列,启动一些线程,让它们单独打开文件(FileSharing.Read,以便它们都可以一次访问文件)以及然后让他们开始从队列中抓取工作。将结果输出到另一个集合中。如果订单对于输出很重要,则按输出顺序排列它们。

---编辑---

你有没有试过ReadFileScatter APIHere's a P-invoke signature from pinvoke.net

+0

+1了解问题。我相信这就是发生了什么,在第二次读取需要完成时,磁盘已经旋转,因此我正在寻找一种方法来执行硬件排队。 – andreialecu 2009-08-21 08:11:09

+0

我原以为Windows会为你处理硬件排队。 C#基础上的硬盘肯定无法获得中世纪的成就。你只能说“去这里读X字节”。我将尝试使用多个线程的不同访问模式。如果2个线程读取A和B,然后读取C和D,也许会更快;或者可能是A和M,然后是B和N. – 2009-08-25 02:54:36

+0

ReadFileScatter API听起来很有前途。我的答案中添加了一个blurb。 – 2009-09-16 19:38:41

0

制作一个单个后台线程作为磁盘代理。将所有读取操作发送给它,并对其进行排序并合并读取。如果两个或两个以上区域接近,则读取包含它们的完整扇区并记录数据的子部分。异步返回数据。

+0

这些读取已经排序,并且FileStream本身已经在默认情况下执行了这种缓冲 - 理由是为什么性能不是完全可怕的。请参阅以下链接以确认缓冲是否确实发生:http://blogs.msdn.com/brada/archive/2004/04/15/114329.aspx – andreialecu 2009-08-20 23:27:00

0

只是为了记录:

在POSIX环境中,您可以使用readv功能请求文件的多个区域有一个(SYS-)调用。 POSIX环境中的另一个选项是非阻塞IO。