我在RAID 5(4 x 7.2k@3TB)系统上有一些2TB只读(创建后不写入)文件。
现在我有一些线程想要读取该文件的部分内容。每个线程都有一个所需的块数组。每个块都通过要读取的文件偏移量(位置)和大小(大多约为300字节)来寻址。
读取这些数据的最快方法是什么。我不在乎CPU周期,(磁盘)延迟才是最重要的。所以如果可能的话,我想利用硬盘的NCQ。
由于文件是高度压缩的,将随机访问,我知道确切的位置,我没有其他方法来优化它
- 我应该将文件读取集中到一个线程吗
- 我应该把文件打开吗
- 每个线程(大约30个)应该同时打开每个文件吗?(来自web服务器的)新线程是什么
- 如果我等待100毫秒并按文件偏移量(先最低)对读数进行排序,会有帮助吗
读取数据的最佳方式是什么?你有经验、技巧、提示吗?
并行请求的最佳数量在很大程度上取决于应用程序之外的因素(例如磁盘数量=4,NCQ深度=?,驱动程序队列深度=?…),因此您可能希望使用一个可以适应或可适应的系统。我的建议是:
- 将所有读取请求与一些元数据一起写入队列,以便通知请求线程
- 让N个线程从该队列中出列,同步读取块,通知请求线程
- 使N运行时可变
- 由于CPU不是您关心的问题,您的工作线程可以计算浮动延迟平均值(和/或最大值,具体取决于您的需要)
- 上下滑动N,直到达到最佳点
为什么要同步读取?它们的延迟低于ascync读取。为什么要在队列上浪费延迟?一个好的无锁定队列实现的启动延迟小于10ns,远小于两个线程切换
更新:一些问答
读取线程是否应该保持文件打开是的,确实如此。
你会将FileStream与FileOptions.RandomAccess一起使用吗是
你写"同步读取区块"。这是否意味着每个读取线程都应该在退出读取区块的顺序后立即开始从磁盘读取区块是的,这就是我的意思读取请求的队列深度由线程数管理。
磁盘是"单线程"的,因为只有一个头。无论你使用多少线程,它都不会更快。。。事实上,更多的线程可能只会减慢速度。只需获取列表并在应用程序中进行排列即可。
当然,你可以使用许多线程来提高NCQ的使用效率,但在应用程序中安排它并使用一个线程应该会更好。
如果文件是碎片化的,请使用NCQ和几个线程,因为这样您就无法知道磁盘上的确切位置,所以只有NCQ才能优化读取。如果是连续的,请使用排序。
您也可以尝试直接I/O以绕过操作系统缓存并按顺序读取整个文件。。。它有时会更快,尤其是在这个数组上没有其他负载的情况下。
ReadFileScatter
会执行您想要的操作吗?