窗口 – 微小读取(重叠,缓冲)的表现超过大型连续读取?
(对于稍长的介绍道歉)
在开发将整个大文件(> 400MB)预先保存到缓冲区高速缓存中以加速实际运行的应用程序之前,我测试了一次读取4MB是否仍然具有比一次读取1MB大小的显着优点。令人惊讶的是,较小的请求实际上变得更快。这似乎是反直觉的,所以我进行了更广泛的测试。 缓冲区缓存在运行测试之前被清除(只是为了笑,我也在缓冲区中的文件中运行缓冲区高速缓存缓存缓存缓存缓存缓存高达2GB / s,无论请求大小如何,尽管有惊人的/ – 30%随机方差)。 结果真的很令人惊讶: 4MB x 256 : 5ms per request,completion 25.8s @ ~40 MB/s 1MB x 1024 : 11.7ms per request,completion 23.3s @ ~43 MB/s 32kB x 32768 : 12.6ms per request,completion 15.5s @ ~66 MB/s 16kB x 65536 : 12.8ms per request,completion 13.5s @ ~75 MB/s 因此,这表明提交数千个请求的长度实际上比提交数百个大型,连续的读取更好。提交时间(ReadFile返回之前的时间)随着请求数量的增加而大幅度增加,但异步完成时间几乎减半。 有什么想法可以解释吗也许这里有人对Windows重叠IO的内部工作有更深入的了解?或者,您可以使用ReadFile读取一兆字节数据的想法有什么实质性的错误? 我可以看到IO调度程序如何通过最小化搜索来优化多个请求,特别是当请求是随机访问(它们不是!)时)。我还可以看到硬盘在NCQ中有几个请求能够执行类似的优化。 Sidenote:明显的赢家是记忆映射。我几乎倾向于增加“不奇怪”,因为我是记忆映射的大粉丝,但在这种情况下,它实际上让我感到惊讶,因为“请求”更小,操作系统应该能够预测更少,安排IO。我没有开始测试内存映射,因为它似乎是反直觉的,它可能能够远程竞争。呃这么多的直觉呢 以不同的偏移重复映射/解映射实际上几乎为零。使用一个16MB的视图和错误的每个页面与一个简单的for()循环读取单个字节每页完成在9.2秒@?111 MB / s。 CPU使用率始终在3%以下(一核心)。相同的电脑,同样的磁盘,一切都一样。 同样看来,Windows一次只能将8页加载到缓冲区缓存中,但实际上只创建了一个页面。每第8页的故障以相同的速度运行,并从磁盘加载相同数量的数据,但显示较低的“物理内存”和“系统缓存”度量,并且只有页面错误的1/8。随后的读取证明页面在缓冲区高速缓存中是明确的(没有延迟,没有磁盘活动)。 (可能非常非常与Memory-Mapped File is Faster on Huge Sequential Read?相关) 为了更多的说明: 更新: 使用FILE_FLAG_SEQUENTIAL_SCAN似乎有些“平衡”读取128k,提高了100%的性能。另一方面,它严重影响512k和256k的读取(你必须想知道为什么),并且对其他任何东西都没有真正的影响。较小的块大小的MB / s图可以说似乎更“偶”,但运行时没有差别。 我可能已经找到一个更小的块大小表现更好的解释。如你所知,异步请求可以同步运行,如果操作系统可以立即提供请求,即从缓冲区(以及针对各种特定于版本的技术限制)。 当考虑实际异步和“立即”异步读取时,注意到高于256k,Windows异步运行每个异步请求。即使它们不能立即使用(即ReadFile只是同步运行),更大的请求被“立即”提供。我不能做出明确的模式(如“前100个请求”或“超过1000个请求”),但是请求大小和同步性之间似乎存在反相关。在8k的块大小时,每个异步请求都是同步的。 对于内存映射预失效,FILE_FLAG_SEQUENTIAL_SCAN会导致性能图形稍微不同的形状(有一个“缺口”被向后移动),但总时间完全相同(再次,这是令人惊讶的,但我不能帮助它)。 更新2: 无缓冲的IO使得1M,4M和512k请求测试用例的性能曲线在GB / s的90年代更高,更“spiky”的最大值,但是在苛刻的最小值的情况下,1GB的整体运行时间在/ – 0.5s的缓冲运行(具有较小缓冲区大小的请求完成速度明显更快,但是这是因为超过2558个空中请求,返回了ERROR_WORKING_SET_QUOTA)。在所有无缓冲的情况下,测量的CPU使用率为零,这是不奇怪的,因为发生的任何IO都会通过DMA运行。 FILE_FLAG_NO_BUFFERING的另一个非常有趣的观察是它显着改变了API行为。 CancelIO不再起作用,至少没有取消IO的意义。在无缓冲的机上请求中,CancelIO将会被阻止,直到所有请求完成。一名律师可能会认为,这个职能不能因为忽视其职责而承担责任,因为在返回时没有更多的飞行中请求,所以在某种程度上它已经做了所要求的 – 但是我对“取消”的理解有点不一样 另一个有趣的是,在所有请求完成或失败之前,该进程是不可用的。如果操作系统正在将DMA写入该地址空间,这种做法是有道理的,但这是一个令人惊叹的“功能”。
我不是一个文件系统专家,但我认为这里有几件事情。首先。 w.r.t.你对记忆映射的评论是赢家。这不是完全令人惊讶的,因为NT缓存管理器是基于内存映射的 – 通过自己做内存映射,你正在复制缓存管理器的行为,而不需要额外的内存副本。
当您从文件中顺序读取时,缓存管理器会尝试为您预取数据,因此您可能会在缓存管理器中看到readahead的影响。在某些时候,缓存管理器停止预取读取(或者在某些时候,预取的数据不足以满足您的读取,因此缓存管理器必须停止)。这可能解释了您看到的较大I / O的放缓。 您是否尝试将FILE_FLAG_SEQUENTIAL_SCAN添加到您的CreateFile标志?这意味着预取器更具侵略性。 这可能是反直觉的,但传统上从磁盘读取数据的最快方法是使用异步I / O和FILE_FLAG_NO_BUFFERING。当您这样做时,I / O直接从磁盘驱动程序进入您的I / O缓冲区,没有任何方法妨碍(假设文件的段是连续的 – 如果不是,文件系统将必须发出几个磁盘读取以满足应用程序读取请求)。当然这也意味着你失去了内置的预取逻辑,并且必须自己滚动。但是使用FILE_FLAG_NO_BUFFERING可以完全控制您的I / O管道。 要记住的另一件事情是:当您进行异步I / O时,务必确保始终有一个I / O请求,而不是在最后一个I / O完成和下一个I / O之间失去潜在的时间开始了 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 构建良好的Windows程序
- wpf – 如何将MenuItem.Header绑定到Window / UserControl依
- OpenProcess:仅在Windows 8.1上访问被拒绝错误
- 如何在Windows 7上启用dhcp客户端的调试
- windows-server-2008 – 在计划中重启服务器是否对性能有好
- 批处理文件 – Dos批处理 – 基本if / else不工作
- 使用CopSSH和MSysGit从Windows克隆git存储库
- 是否有任何Windows模拟器可用于测试iPhone应用程序?
- 在Windows远程服务器中运行命令,并在C#.NET中获取控制台输出
- 是否有用于向任务栏图标添加徽章的Windows API?
- windows-runtime – 在WinRT中创建只读依赖项属性
- 如何在Windows和Unix / Linux格式之间转换文本文
- windows-phone-7 – WP 8:如何从Visual Studio部
- 如何在Windows Server 2016上运行Linux Docker镜
- MDT2013批量升级Win7客户端至Win10
- windows – “预定义的计算机集”,在哪里定义?
- windows – 为什么最大化的Delphi形式比GetSyste
- disk-image – 如何在Windows 7 WinPE中安装ISO映
- windows-server-2008-r2 – 任务管理器性能“物理
- Win2000?Server入侵监测揭秘