C# 按2TB文件的文件偏移量随机读取300字节块的最快方法?

C# 按2TB文件的文件偏移量随机读取300字节块的最快方法?,c#,.net,file-io,binary-data,C#,.net,File Io,Binary Data,我在RAID 5(4 x 7.2k@3TB)系统上有一些2TB只读(创建后不写)文件 现在我有一些线程想要读取该文件的部分内容。 每个线程都有它所需要的块数组。 每个块都通过文件偏移量(位置)和读取大小(主要是300字节)来寻址 读取这些数据的最快方式是什么。 我不在乎CPU周期,(磁盘)延迟才是最重要的。 所以如果可能的话,我想利用硬盘的NCQ 由于文件是高度压缩的,并且会随机访问,而且我确切地知道位置,所以我没有其他方法来优化它 我应该将文件读取集中到一个线程吗 我应该把文件打开吗 如果每

我在RAID 5(4 x 7.2k@3TB)系统上有一些2TB只读(创建后不写)文件

现在我有一些线程想要读取该文件的部分内容。 每个线程都有它所需要的块数组。 每个块都通过文件偏移量(位置)和读取大小(主要是300字节)来寻址

读取这些数据的最快方式是什么。 我不在乎CPU周期,(磁盘)延迟才是最重要的。 所以如果可能的话,我想利用硬盘的NCQ

由于文件是高度压缩的,并且会随机访问,而且我确切地知道位置,所以我没有其他方法来优化它

  • 我应该将文件读取集中到一个线程吗
  • 我应该把文件打开吗
  • 如果每个线程(大约30个)都同时打开每个文件,那么(来自web服务器的)新线程是什么呢
  • 如果我等待100毫秒并按文件偏移量(最低的第一个)对读数进行排序,会有帮助吗
读取数据的最佳方式是什么?你有经验、技巧和提示吗?

磁盘是“单线程”的,因为只有一个磁头。无论你使用多少线程,它都不会运行得更快。。。事实上,更多的线程可能只会减慢速度。只需在应用程序中获取列表并对其进行排列(排序)

当然,你可以使用多个线程来提高NCQ的使用效率,但是在应用程序中安排它并使用一个线程应该会更好

如果文件是碎片化的-请使用NCQ和几个线程,因为这样您就无法知道磁盘上的确切位置,所以只有NCQ可以优化读取。如果是相邻的,则使用排序


您也可以尝试直接I/O绕过操作系统缓存,按顺序读取整个文件。。。它有时会更快,尤其是在这个阵列上没有其他负载的情况下。

会做你想做的事吗?

并行请求的最佳数量在很大程度上取决于你的应用程序之外的因素(例如,磁盘数=4,NCQ深度=?,驱动程序队列深度=?),因此你可能想要使用一个可以适应或可以适应的系统。我的建议是:

  • 将所有读取请求连同允许通知请求线程的元数据一起写入队列
  • 让N个线程从该队列中出列,同步读取区块,通知请求线程
  • 使N运行时可变
  • 由于CPU不是您关心的问题,您的工作线程可以计算浮动平均延迟(和/或最大延迟,取决于您的需要)
  • 向上和向下滑动N,直到到达最低点
为什么同步读取?它们比ascync读取具有更低的延迟。 为什么要在队列上浪费延迟?一个好的无锁队列实现从小于10ns的延迟开始,远远少于两个线程切换

更新:一些问答


读取线程应该保持文件打开吗是的,绝对如此。

是否将FileStream与FileOptions.RandomAccess一起使用


你写“同步读取块”。这是否意味着每一个读线程都应该在退出读块命令后立即开始从磁盘读取块是的,这就是我的意思。读取请求的队列深度由线程数管理。

-1。如果您有多个thjreads,则多个requets会命中光盘。好的光盘(SAS、SATA)允许光盘重新排序以提高效率(“本机命令队列”),并以其他顺序提供结果。与普通同步单线程IO相比,这给了您一个显著的提升。因此,每个磁盘都可以从其他位置读取。此外,重新读取的块非常小,因此使用RAID5和大多数控制器一次读取一个完整的条带,很可能RAM中已经存在另一个块。读取线程是否应该保持文件打开?我想是的。是否将FileStream与FileOptions.RandomAccess一起使用?你写“同步读取块”。这是否意味着每一个读线程都应该在退出读块命令后立即开始从磁盘读取块?编辑了我的答案,试图回答您的评论。我忘了,您写道:“良好的无锁队列实现在小于10ns的延迟时开始”。你有一个特别的类/项目吗?我有:我写了一个,因为通常的怀疑没有扩展(甚至在一个简单的8核系统上也没有)。我想是时候把它开源了。你会接受LGPL吗?这意味着在一个单独的DLL中使用LocklessQueue,您可以在商业项目中使用它。很酷,谢谢。是的,LGPL还可以。我会把它弄得一团糟,然后在源代码中阅读您的注释。但是一个非常小的示例代码如何使用它将非常适合您的项目。好的,通过阅读源代码,我认为我可以自己看到它。