使用多个线程的硬盘争用

时间:2017-03-12 00:50:45

标签: c++ multithreading

我还没有对此进行任何配置文件测试,但是对于使用多个线程与一个线程的硬盘加载资源的优缺点,一般会有什么共识?注意。我不是在讨论主线程。

我原本以为使用了多个"其他"线程做加载是没有意义的,因为HD不能同时做两件事,因此肯定只会引起磁盘争用。

不确定在架构上走哪条路,欣赏任何建议。

编辑:道歉,我的意思是说SSD驱动器不是磁盘驱动器。对我来说两者都是高清,但我对具有单个SSD驱动器的系统更感兴趣。

正如评论中所指出的,使用多个线程的一个优点是大文件加载不会延迟向线程加载器的接收器呈现较小的文件。在我的情况下,这是一个很大的优势,因此,即使它需要一点点性能,也需要多线程。

我知道没有简单的答案,但我要问的真正问题是,将并行磁盘写入顺序(在OS层中)而不是仅允许1个资源加载器会有什么样的性能%惩罚线?是什么因素推动了这一点?我不是指平台,制造商等。我的意思是技术上,OS / HD交互的哪些方面会影响这种惩罚? (理论上)。

进一步编辑: 我的确切用例是纹理加载线程,只存在从HD加载然后"传递"他们在opengl上,所以在线程中有最小的计算(可能是某种类型的转换等)。在这种情况下,线程将花费大部分时间等待HD(我想到的),因此如何管理OS-HD交互是很重要的。我的操作系统是Windows 10。

3 个答案:

答案 0 :(得分:2)

  

请注意。我不是在讨论主线程。

主要与非主要线程对读取磁盘的速度没有区别。

  

我原本以为使用了多个"其他"由于HD不能同时做两件事,所以线程做加载是没有意义的,因此肯定只会引起磁盘争用。

事实上。尝试的并行读取不仅被迫等待彼此(因此实际上不是并行),而且它们还将使磁盘的访问模式随机而不是顺序,这由于磁头搜索时间而慢得多。

当然,如果您要处理多个硬盘,那么每个驱动器专用的一个线程可能是最佳的。

现在,如果您使用的是固态驱动器而不是硬盘驱动器,那么情况就不那么明确了。多个线程可能更快,更慢或更具可比性。可能涉及很多因素,如固件,文件系统,操作系统,相对于其他瓶颈的驱动速度等。

在任何一种情况下,RAID都可能使此处的假设无效。

答案 1 :(得分:1)

很多人会告诉你,高清不能同时做多件事。这并不完全正确,因为现代IO系统有很多间接性。用一个线程很难对它们进行饱和。

以下是我遇到的多线程IO帮助的三种情况。

  1. 有时,IO读取库具有非常重要的计算量,考虑读取压缩视频,或者在传输发生后进行奇偶校验检查。一个例子是使用robocopy和多个线程。使用128个线程启动robocopy并不罕见!

  2. 许多操作系统的设计使得单个进程无法使IO饱和,因为这会导致系统无响应。在一个案例中,我的读取速度提高了3%,因为我接近使IO饱和。如果存在将数据条带化到不同驱动器的系统策略,则可能会在HPC群集中的Lustre驱动器上设置,这是双重的。对于我的应用程序,最佳线程数是两个。

  3. 更复杂的IO,就像RAID卡一样,包含大量缓存,可以让HD头不断读写。为了获得最佳吞吐量,您需要确保无论何时头部旋转其不断读/写而不仅仅是移动。实际上,实现此目的的唯一方法是使卡的板载RAM饱和。

  4. 因此,很多时候你可以通过使用多个线程重叠一些少量的计算,并且随着更大的磁盘阵列,东西开始变得棘手。

      

    不确定在架构上走哪条路,欣赏任何建议。

    确定每个线程的工作量是最常见的架构优化。编写代码使其易于增加IO工作量。你需要进行基准测试。

答案 2 :(得分:1)

这取决于您要处理的数据量。这将确定应用程序是您绑定的I / O还是计算绑定。

例如,如果您要对数据做的只是一些简单的算术,例如加1,然后你最终会被I / O绑定。 CPU可以比任何I / O系统提供数据流更快地将数据加1。

但是,如果您要对每批数据进行大量工作,例如一个FFT,然后是一个滤波器,然后是一个卷积(我在这里选择随机DSP例程名称),那么你可能最终会被计算限制; CPU无法跟上拥有SSD的I / O子系统提供的数据。

判断一个算法应该如何构建以匹配底层机器的底层功能是非常艺术的,反之亦然。有像FTRACE / Kernelshark,英特尔的VTune这样的分析工具,它们都可用于分析究竟发生了什么。谷歌做了很多工作来衡量他们的硬件完成的每瓦搜索量,功耗是他们最大的成本。

一般而言,任何类型的I / O,即使是大量的SSD,也都非常缓慢。与CPU可以消耗的内容相比,即使是PC(DDR4)中的主内存也非常缓慢。与CPU内核相比,即使是L3和L2缓存也是懒散的。很难设计和多线程化算法,以便在每个数据项处于L1缓存时完成适当的工作量,以便L2,L3缓存,DDR4和I / O子系统可以及时将下一个数据项传递给L1高速缓存,以保持CPU核心的繁忙。对于使用不同CPU,SSD或内存SIMM的另一台机器而言,理想的软件设计可能毫无希望。英特尔设计具有良好的通用计算机性能,实际上从单个程序中提取峰值性能是一项真正的挑战。像英特尔的MKL和IPP这样的图书馆在这方面做了很大的帮助。

一般指导

一般来说,人们应该根据任何特定线程排列所需的数据带宽来看待它,以及那些线程正在做的工作。

这意味着对程序的内部处理循环进行基准测试,并测量它处理的数据量以及设法完成的速度,选择一些有意义的数据项,但远远超过L3缓存的大小。单个数据项'是一定数量的输入数据,相应的输出数据量,以及用于处理输入到输出的任何变量,其总大小适合L1缓存(有一些空余空间)。并且不作弊 - 在适当的情况下使用CPU SSE / AVX指令,不要使用英特尔的IPP / MKL之类的东西写简单C来放弃它们。 [虽然如果一个人正在使用IPP / MKL,它会尽最大努力为你做这一切。]

目前DDR4内存对20到100GByte /秒之间的任何内容都有好处(取决于CPU,SIMM的数量等),只要您不对数据进行随机,分散的访问。通过使L3饱和,你的强迫自己受到DDR4速度的束缚。然后,您可以开始更改代码,增加每个线程在单个数据项上完成的工作。继续增加每个项目的工作量,速度最终会开始增加;你已经达到了不再受DDR4速度限制的程度,然后是L3,然后是L2。

如果在此之后您仍然可以看到增加每个数据项的工作的方法,那么继续前进。您最终会获得接近IO子系统的数据带宽,然后才能获得绝对最大的机器数据带宽。

这是一个迭代过程,经验允许人们将其缩短。

当然,如果一个人没有想法来增加每个数据项的工作量,那么这就是设计过程的结束。只有通过提高最终成为瓶颈的能力(几乎可以肯定是SSD),才能实现更高的性能。

对于我们这些喜欢做这个软件的人来说,PS3的Cell处理器是一个梦想。无需再次猜测缓存,没有。一个人完全控制了数据和代码的位置和时间。