当前位置:  开发笔记 > 运维 > 正文

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

如何解决《如何从磁盘获得良好的并发读取性能》经验,为你挑选了2个好方法。

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

我们有两个大文件,我们想同时从两个独立的线程中读取.一个线程将顺序读取fileA,而另一个线程将顺序读取fileB.线程之间没有锁定或通信,两者都按顺序读取,并且两者都立即丢弃它们读取的数据.

我们在Windows上使用此设置的经验非常差.两个线程的组合吞吐量大约为2-3 MiB/sec.驱动器似乎花费大部分时间在两个文件之间寻找后退和前进,大概在每次搜索后读取很少.

如果我们禁用其中一个线程并暂时查看单个线程的性能,那么我们可以获得更好的带宽(此机器约为45 MiB /秒).很明显,糟糕的双线程性能是操作系统磁盘调度程序的假象.

我们可以做些什么来改善并发线程读取性能? 也许通过使用不同的API或以某种方式调整操作系统磁盘调度程序参数.

一些细节:

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

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

每个线程在一个循环中旋转,调用read函数.我们改变了每次迭代从API请求的字节数,从1KiB到128MiB之间的值.改变这一点没有任何影响,因此在每次磁盘搜索之后,OS实际读取的数量不是由这个数字决定的.这正是应该期待的.

单线程和双线程性能之间的巨大差异在Windows 2000,Windows XP(32位和64位),Windows Server 2003以及使用和不使用硬件RAID5时都是可重复的.



1> 小智..:

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

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的值也可以通过检查实际的传输速率自动调整并慢慢修改它们,从而在应用程序在不同的机器和/或操作系统上运行时最大化吞吐量您可以找到缓存,内存或RAID级别以某种方式影响它们,但通过自动调整,您将始终在每种情况下获得最佳性能.



2> pauldoo..:

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

我们的Windows解决方案是将FILE_FLAG_NO_BUFFERING标志传递给CreateFile每次调用时使用大(~16MiB)读取ReadFile.由于以下几个原因,这是次优的:

这样读取时文件不会被缓存,因此缓存通常没有任何优点.

使用此标志时的约束比正常读​​取(读取缓冲区与页面边界的对齐等)复杂得多.

(作为最后的评论.这是否解释了为什么在Windows下进行交换是如此地狱般的?即,Windows无法以任何效率同时对多个文件执行IO,因此在交换所有其他IO操作时,被迫不成比例地缓慢.)


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

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

几个运行Windows 2000,Windows XP(32位)和Windows XP(64位)的单个驱动器的戴尔工作站(英特尔至强).

运行Windows Server 2003(64位)且RAID 1 + 0的Dell 1U服务器(Intel Xeon).

HP工作站(AMD Opteron),带有Windows XP(64位),Windows Server 2003和硬件RAID 5.

我的家用无品牌PC(AMD Athlon64)运行Windows XP(32位),FreeBSD(64位)和Linux(64位),单驱动器.

我的家用MacBook(Intel Core1)运行Mac OS X,单SATA驱动器.

我的家Koolu PC运行Linux.与其他系统相比,它的功能非常不足,但我证明了在进行多线程磁盘读取时,即使是这台机器也可以胜过带有RAID5的Windows服务器.

在测试期间,所有这些系统的CPU使用率都非常低,并且禁用了防病毒软件.

我之前忘了提到,但我们也尝试了标准设置的普通Win32 CreateFileAPI FILE_FLAG_SEQUENTIAL_SCAN.这个标志没有解决问题.

推荐阅读
刘美娥94662
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有