我正在使用包含数据块的只读数据文件(例如,100个演出),每个数据块大约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#错误“无法在锁定语句的主体中等待”)。我不能删除await而不会丢失异步行为。我目前的解决方法是从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);
}
这是构建多线程异步友好缓存的最佳方法吗?还有其他建议吗?
答案 0 :(得分:2)
你确定吗? :) 几十年来,Windows投入了大量的工作来实现内置于操作系统的高性能文件缓存。我想构建一个内存缓存
在某些极端情况下,您可以针对特定用例执行更高效的缓存,但绝大多数情况下,它不值得付出努力。我建议先测量一下。
我无法锁定FStream以使上述线程安全(C#错误&#34;无法在锁定语句的主体中等待#34;)。
我的问题是关于是否/如何以异步方式对FileStream执行多个并发读取
您可以使用SemaphoreSlim
充当async
兼容锁。语法有点尴尬,但它确实有效。
另外,我还建议查看内存映射文件。
答案 1 :(得分:1)
看起来您想要的是以某种方式查找并同时读取文件。幻想的术语是执行“原子搜索和读取”操作。
Windows和Linux支持这种确切类型的操作。在Linux上,有一个名为pread的函数,在Windows上有一个称为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);