C# 中推荐的从单个文件中的多个位置并发和异步读取的方法

Recommended approach in C# to read from multiple locations in a single file concurrently and asynchronously

我正在处理只读数据文件(例如 100 多个 gig),每个文件包含约 64K 的数据块。我想构建一个内存缓存来为处理每个服务请求所需的 10s-100s 块读取提供服务。

基本的异步非线程安全读取如下所示:

public async Task<byte[]> Read(int id)
{
    FStream.Seek(CalcOffset(id), SeekOrigin.Begin);
    var ba = new byte[64 * 1024];
    await FStream.ReadAsync(ba, 0, ba.Length);
    return ba;
}

我无法锁定 FStream 以使上述线程安全(C# 错误 "Cannot await in the body of a lock statement")。我无法在不丢失异步行为的情况下删除等待。我当前的解决方法是从 FileStreams 的缓存中读取绘图:

    private BufferBlock<FileStream> StreamRead;

    public async Task<FileStream> GetReadStream()
    {
        return await StreamRead.ReceiveAsync(TimeSpan.FromMilliseconds(-1));
    }

    public async Task ReleaseReadStream(FileStream stream)
    {
        await StreamRead.SendAsync(stream);
    }

这是构建多线程异步友好缓存的最佳方法吗?还有其他建议吗?

I would like to build an in-memory cache

你确定吗? :)

Windows 几十年来投入了大量工作,以实现 OS.

中内置的极其高效的文件缓存。

在某些极端情况下,您可以针对特定用例进行更高效的缓存,但在绝大多数情况下,这样做是不值得的。我建议先测量。

I can't lock on the FStream to make the above thread-safe (C# error "Cannot await in the body of a lock statement").

My question pertains on whether/how to perform multiple concurrent reads on a FileStream in an async manner

您可以使用 SemaphoreSlim 作为 async 兼容锁。语法有点笨拙,但它有效。

附带说明一下,我还建议查看内存映射文件。

您似乎想要的是以某种方式同时查找和读取文件。花哨的术语是执行 "atomic seek and read" 操作。

Windows 和 Linux 支持这种 确切的操作类型 。在 Linux 上,有一个名为 pread, and on Windows, there's a function called ReadFile 的函数。剩下的就是经历挂接到这些电话的混乱局面。是啊,不好玩。

我遇到了完全相同的问题,所以我将解决方案制作成一个库。呈现,我的图书馆 pread。它允许您同时自动查找和读取,并且比锁定 FileStream 更快。

using pread;

using var fileStream = new FileStream("my_file.txt", FileMode.OpenOrCreate);

var data = new byte[123];

var bytesWritten = P.Write(fileStream, (ReadOnlySpan<byte>)data, fileOffset: 0);
var bytesRead = P.Read(fileStream, (Span<byte>)data, fileOffset: 0);