我想问一个问题,然后用我自己的答案跟进,但也看看其他人有什么答案。
我们有两个大文件,我们想同时从两个单独的线程中读取它们。一个线程将顺序读取fileA,而另一个线程将顺序读取fileB。线程之间没有锁定或通信,它们都在尽可能快地顺序读取,并且都立即丢弃它们读取的数据。
我们在 Windows 上使用此设置的经验非常差。两个线程的总吞吐量约为 2-3 MiB/sec。驱动器似乎花费了大部分时间在两个文件之间来回搜索,可能在每次搜索后读取的很少。
如果我们禁用其中一个线程并暂时查看单个线程的性能,那么我们将获得更好的带宽(这台机器约为 45 MiB/秒)。很明显,糟糕的双线程性能是 OS 磁盘调度程序的产物。
我们可以做些什么来提高并发线程读取性能? 也许通过使用不同的 API 或以某种方式调整 OS 磁盘调度程序参数。
一些细节:
在具有 2GiB 内存的机器上,这些文件的大小约为 2GiB。出于这个问题的目的,我们认为它们没有被缓存和完美碎片整理。我们使用了碎片整理工具并重新启动以确保是这种情况。
我们没有使用特殊的 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 的情况下,单线程和双线程性能之间的巨大差异是可以重复的。