随机偏移的异步 IO
本文关键字:异步 IO 随机 | 更新日期: 2023-09-27 18:33:53
我们有一个 20 GB 的文件,我们希望从中随机偏移量读取数据,因此它不是顺序读取。我计划使用异步 IO,但是我注意到这个限制——
正如我所说,我的要求是随机偏移量阅读。但是,BeginRead API 不会将偏移量引入文件,而只会将偏移量引入要读取到的缓冲区中(http://msdn.microsoft.com/en-us/library/zxt5ahzw)
所以我唯一的选择是使用 FileStream.Seek 。但是,问题是如果我使用异步IO
FileStream fs = Foo.txt 由两个线程使用
Thread 1 Thread 2
fs.Seek(offset1)
(Thread 1 gets preempted)
fs.Seek(offset2)
fs.BeginRead
fs.BeginRead
如您所见,如果线程 1 在 Seek 偏移量 1 之后被抢占,那么线程 1 最终将从 offset2 读取,这不是本意。
这是否意味着我必须使用锁?这将破坏异步 IO 的目的。
完全不清楚这是否适用于您的情况,但请看一下内存映射文件,它可能会给您一些想法。
每个文件流都有自己的偏移量,所以这应该可以工作 - 请参阅下面的示例(完全同步)。
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指针,那么您的生活将更轻松。
顺便说一下,您可以使用同步调用进行非顺序读取 - 它不必是异步的(上面的例子就是这样做的)。添加异步操作通常会带来额外的复杂性,因此您应该查看它是否真的需要。
线程相互等待,则每个线程需要一个 Stream,即使这些访问是异步发生的。
现在,如果您的线程将大部分时间花在执行其他操作上,则可以按需打开流并在完成后将其关闭。流包装本机资源、文件句柄,所以你当然不应该有数百个资源躺在那里,什么都不做。
最后一个选项是管理开放流池。每当线程需要从文件中读取时,将其中一个流分发给线程。完成后,流应返回到池中供其他线程使用。当然,您必须同步对池的访问。
您可以使用"共享文件"访问选项进行读取。
如果不需要读/写共享,而只是读取,则可以减少 FileAccess/文件共享属性。
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