关于Windows:如何从磁盘获得良好的并发读取性能

关于Windows:如何从磁盘获得良好的并发读取性能

How to obtain good concurrent read performance from disk

我想问一个问题,然后用我自己的答案跟进,但还要看看其他人有什么答案。

我们有两个大文件,希望同时从两个单独的线程中读取。一个线程将顺序读取fileA,而另一个线程将顺序读取fileB。线程之间没有锁定或通信,它们都以尽可能快的速度顺序读取,并且都立即丢弃读取的数据。

我们在Windows上使用此设置的经验非常差。两个线程的合并吞吐量约为2-3 MiB / sec。该驱动器似乎在大部分时间上都在两个文件之间来回搜索,大概每次搜索后读取的内容很少。

如果我们禁用其中一个线程并暂时查看单个线程的性能,那么我们将获得更好的带宽(这台机器约为45 MiB /秒)。因此很明显,糟糕的两线程性能是OS磁盘调度程序的假象。

有什么办法可以改善并发线程的读取性能?也许通过使用不同的API或通过某种方式调整OS磁盘调度程序参数。

一些细节:

在具有2GiB RAM的计算机上,每个文件的顺序为2 GiB。出于这个问题的目的,我们认为它们不会被缓存和完美地进行碎片整理。我们使用了碎片整理工具并重新启动以确保是这种情况。

我们没有使用特殊的API来读取这些文件。该行为在各种沼泽标准API(例如Win32的CreateFile,C的fopen,C ++的std :: ifstream,Java的FileInputStream等)中都是可重复的。

每个线程旋转一个循环,以调用read函数。我们将每次迭代从API请求的字节数从1KiB到128MiB之间的值进行了更改。改变它没有任何作用,因此很明显,每个磁盘搜索之后操作系统的物理读取量不受此数字的限制。这正是应该期望的。

在Windows 2000,Windows XP(32位和64位),Windows Server 2003以及带有或不带有硬件RAID5的情况下,单线程和双线程性能之间的巨大差异是可重复的。


问题似乎出在Windows I / O调度策略中。根据我在这里找到的信息,有多种方法可以进行O.S.安排磁盘请求。尽管Linux和其他操作系统可以在不同的策略之间进行选择,但在Vista Windows被锁定为单个策略之前:FIFO队列,其中所有请求均分成64 KB的块。我认为,此策略是导致您遇到问题的原因:调度程序将混合来自两个线程的请求,从而导致在磁盘的不同区域之间进行连续查找。
现在,好消息是,根据此处和此处的内容,Vista引入了一个更智能的磁盘调度程序,您可以在其中设置请求的优先级,还可以为您的进程分配最小的错误宽度。
坏消息是,我找不到在以前版本的Windows中更改磁盘策略或缓冲区大小的方法。同样,即使提高进程的磁盘I / O优先级可以提高其他进程的性能,但仍然存在线程相互竞争的问题。
我可以建议通过引入自制磁盘访问策略来修改软件。
例如,您可以在线程B中使用这样的策略(与线程A类似):

1
2
3
if THREAD A is reading from disk then wait for THREAD A to stop reading or wait for X ms
Read for X ms (or Y MB)
Stop reading and check status of thread A again

您可以使用信号量进行状态检查,也可以使用perfmon计数器获取实际磁盘队列的状态。
X和/或Y的值也可以通过检查实际的传输速率并缓慢修改它们来自动调整,从而在应用程序在不同的计算机和/或OS上运行时最大化吞吐量。您可能会发现缓存,内存或RAID级别以某种方式影响它们,但是通过自动调整,您将始终在每种情况下都获得最佳性能。


我想在回复中添加一些其他说明。我们测试过的所有其他非Microsoft操作系统都不会遇到此问题。从一个线程转移到两个线程时,Linux,FreeBSD和Mac OS X(最后一个版本在不同的硬件上)在聚合带宽方面的降幅要大得多。例如,Linux从?45 MiB / sec降级到?42 MiB / sec。这些其他操作系统必须在每次搜索之间读取文件的更大块,因此,几乎不会花费所有时间在磁盘上等待搜索。

我们针对Windows的解决方案是将FILE_FLAG_NO_BUFFERING标志传递给CreateFile,并在每次对ReadFile的调用中使用较大的读取(?16MiB)。这是次优的,原因如下:

  • 像这样读取时文件不会被缓存,因此缓存通常不会带来任何好处。
  • 使用该标志时的约束比正常读??取要复杂得多(读取缓冲区与页面边界对齐等)。

(最后一点。这是否解释了为什么在Windows下进行交换如此令人讨厌?即Windows无法以任何效率同时对多个文件执行IO,因此在交换所有其他IO操作时被迫变得异常缓慢。)

编辑以添加有关Will Dean的更多详细信息:

当然,在这些不同的硬件配置中,原始数据确实发生了变化(有时会发生很大变化)。但是,问题是从一个线程转移到两个线程时,只有Windows会遭受性能的持续下降。以下是测试机器的摘要:

  • 多个不同年龄的Dell工作站(Intel Xeon),它们使用单??个驱动器运行Windows 2000,Windows XP(32位)和Windows XP(64位)。
  • 运行带有RAID 1 + 0的Windows Server 2003(64位)的Dell 1U服务器(Intel Xeon)。
  • 具有Windows XP(64位),Windows Server 2003和硬件RAID 5的HP工作站(AMD Opteron)。
  • 我的家用无品牌PC(AMD Athlon64),运行Windows XP(32位),FreeBSD(64位)和Linux(64位)并带有单个驱动器。
  • 我的家用MacBook(Intel Core1)运行Mac OS X,单个SATA驱动器。
  • 我的家用Koolu PC运行Linux。与其他系统相比,它的功能严重不足,但我展示了在进行多线程磁盘读取时,即使该计算机也可以胜过具有RAID5的Windows服务器。

在测试过程中,所有这些系统上的CPU使用率都很低,并且禁用了防病毒功能。

我之前忘记提及,但我们也尝试了设置FILE_FLAG_SEQUENTIAL_SCAN标志的普通Win32 CreateFile API。此标志不能解决问题。


您在相当广泛的Windows版本中看不到任何区别,并且在单个驱动器和硬件raid-5之间没有任何区别,这似乎有些奇怪。

只是"胆量",但这确实使我怀疑这确实是一个简单的寻求问题。除了OS X和Raid5,所有这些都在同一台机器上尝试过-您是否尝试过另一台机器?在此测试期间,您的CPU使用率是否基本为零?

您能写出的最短的应用程序证明了这个问题? -我想在这里尝试一下。


保罗-看到了更新。很有意思。

在Vista或Win2008上试用它会很有趣,因为人们似乎在某些情况下报告了这些方面的相当大的I / O改进。

我对不同API的唯一建议是尝试使用内存映射文件-您是否尝试过?不幸的是,每个文件只有2GB,您将无法在32位计算机上映射多个完整文件,这意味着它并不是那么简单。


您是否在Windows下使用IOCompletionPorts?通过C ++的Windows对此主题有深入的介绍,很幸运,它也可以在MSDN上获得。


我会在内存线程中创建某种安全锁。每个线程可以等待锁定,直到释放为止。锁定释放后,获取锁定并在规定的时间长度或定义的数据量内读取文件,然后为其他等待线程释放锁定。


推荐阅读

    无法读取U盘中的数据

    无法读取U盘中的数据,,核心提示:我有一个512MB的U盘,把它插在电脑显示器里面是空的,但右键单击以查看已经使用USB 480mb文件的属性未设置为隐

    提高3A四核羿龙II游戏配置的性能

    提高3A四核羿龙II游戏配置的性能,,以节能环保为主题的IT产业,目前3A低端平台处理器、主板芯片组、独立开发卡性能突出,特别是在与AMD的处理

    优化PostgreSQL中的批量更新性能

    优化PostgreSQL中的批量更新性能,数据,表格,在Ubuntu 12.04上使用PG 9.1. 我们目前需要24小时才能运行大量UPDATE数据库上的语句,其形式

    诺基亚威图性能好到哪里

    诺基亚威图性能好到哪里,诺基亚,手机,诺基亚威图性能好到哪里这是一部以前列出的手机。即使当时配置不高,该品牌的手机也不依赖于该功能吸

    魅蓝note6性能参数有哪些

    魅蓝note6性能参数有哪些,摄像头,蓝牙,魅蓝note6性能参数有哪些魅力蓝色Note6最好拍照。电池寿命更长。蓝色Note6使用高通 snapdragon 625

    电脑硬盘分区重装|电脑重装磁盘分区

    电脑硬盘分区重装|电脑重装磁盘分区,,1. 电脑重装磁盘分区1、新买的原装的电脑,不需要重新分区和装系统,已经是分区装好了系统的。2、如果是