1

我们有一个 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 的目的。

4

4 回答 4

2

完全不清楚这是否适用于您的情况,但看看内存映射文件,它可能会给您一些想法。

于 2012-05-10T23:42:26.400 回答
1

如果您不希望线程彼此等待,那么每个线程都需要一个 Stream,即使这些访问是异步发生的。

现在,如果您的线程大部分时间都在做其他事情,那么您可以按需打开流并在完成后关闭它。流封装了原生资源、文件句柄,所以你当然不应该有数百个它们,什么都不做。

最后一个选项是管理开放流池。每当线程需要从文件中读取时,将其中一个流分发给线程。完成后,应将流返回到池中以供其他线程使用。您当然必须同步对池的访问

于 2012-05-11T00:39:11.553 回答
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 指针,那么您的生活会更轻松。

顺便说一句,您可以使用同步调用进行非顺序读取 - 它不必是异步的(上面的示例就是这样做的)。添加异步操作通常会带来额外的复杂性,因此您应该看看它是否真的需要。

于 2012-05-10T23:08:01.790 回答
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
于 2012-05-11T01:18:03.517 回答