我们有一个20 GB的文件,我们想从中随机读取数据,因此它不是顺序读取的。我打算使用异步IO,但我注意到这个限制 -
正如我所说,我的要求是随机读取偏移量。但是,BeginRead API不会在文件中占用偏移量,它只会在读取的缓冲区中占用偏移量 (http://msdn.microsoft.com/en-us/library/zxt5ahzw)所以我唯一的选择是使用FileStream.Seek。但问题是,如果我使用的是异步IO
两个线程
使用FileStream fs = Foo.txtThread 1 Thread 2
fs.Seek(offset1)
(Thread 1 gets preempted)
fs.Seek(offset2)
fs.BeginRead
fs.BeginRead
正如你可以看到线程1在Seek偏移1之后被抢占一样,那么线程1将最终从offset2读取而不是意图。
这是否意味着我必须使用锁?这会破坏异步IO的目的。
答案 0 :(得分:2)
一点也不清楚,如果这适用于您的情况,但是给memory mapped files看看,它可能会给你一些想法。
答案 1 :(得分:1)
每个文件流都有自己的偏移量,所以这应该可行 - 请参阅下面的示例(完全同步)。
public class StackOverflow_10543252
{
public static void Test()
{
byte[] bytes = Enumerable.Range(0, 256).Select(i => (byte)i).ToArray();
File.WriteAllBytes("a.bin", bytes);
FileStream fs1 = File.OpenRead("a.bin");
fs1.Seek(40, SeekOrigin.Begin);
FileStream fs2 = File.OpenRead("a.bin");
fs2.Seek(120, SeekOrigin.Begin);
Console.WriteLine(fs1.ReadByte()); // should be 40
Console.WriteLine(fs2.ReadByte()); // should be 120
fs1.Close();
fs2.Close();
File.Delete("a.bin");
}
}
更新:发布此答案后看到了编辑。如果您只需要1个FileStream
指针(可能需要也可能不需要),那么您需要使用一些锁定来防止两个并发操作相互重叠。但是如果你可以使用多个FileStream指针,那么你的生活会更容易。
顺便说一句,你可以使用同步调用进行非顺序读取 - 它不必是异步的(上面的例子就是这样)。添加异步操作通常会带来额外的复杂性,因此您应该看看它是否真的需要。
答案 2 :(得分:1)
如果您不希望线程彼此等待,那么每个线程需要一个Stream ,即使这些访问是异步发生的。
现在,如果你的线程花费大部分时间做其他事情,那么你可以按需打开流并在完成后关闭它。 Streams包装了本机资源,文件句柄,所以你当然不应该有数百个它们四处闲置,什么都不做。
最后一个选项是管理一个开放流池。每当线程需要从文件中读取时,将其中一个流分发给该线程。完成后,应将流返回池中以供其他线程使用。您当然必须同步对池的访问。
答案 3 :(得分:0)
您可以使用“共享文件”访问选项进行读取。
如果您不需要读/写共享而只是阅读,则可以减少FileAccess / FileShare属性。
Using f As FileStream = mTransferFile.Open(FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.ReadWrite)
Dim newPosition As Long = t.ID * mTransferInfo.BlockSize
f.Position = newPosition
'Do stuff here. Open another filestream etc.
End Using