【问题标题】:What is the optimal number of threads for performing IO operations in java?在 java 中执行 IO 操作的最佳线程数是多少?
【发布时间】:2010-11-17 09:59:50
【问题描述】:

在 Goetz 的“Java Concurrency in Practice”中,在第 101 页的脚注中,他写道“对于此类不 I/O 且不访问共享数据的计算问题,Ncpu 或 Ncpu+1 线程产生最佳吞吐量;更多线程没有帮助,实际上可能会降低性能......"

我的问题是,在执行文件写入、文件读取、文件删除等 I/O 操作时,是否有关于使用线程数来实现最大性能的准则?我知道这只是一个指导数字,因为磁盘速度和许多其他因素都会影响到这一点。

不过,我想知道:20 个线程将 1000 个单独的文件写入磁盘的速度是否比 4 个 CPU 机器上的 4 个线程更快?

【问题讨论】:

    标签: java multithreading io


    【解决方案1】:

    实际上,I/O 密集型应用程序仍然可以从多线程中获益良多,因为并行读取或写入几个文件比顺序读取或写入文件要快得多。在整体吞吐量受到网络延迟影响的情况下尤其如此。但也有这样的情况,一个线程可以在另一个线程忙于读取时处理它读取的最后一个内容,从而允许更高的 CPU 利用率。

    我们可以整天谈论理论,但正确的答案是使线程数可配置。我想你会发现将它增加到超过 1 会提高你的速度,但也会出现收益递减点。

    【讨论】:

    • 听起来 OP 是在谈论让所有线程执行相同的操作,而不是一个读取和一个进程。
    • 好吧,如果每个线程都在读取然后处理不同的文件,你仍然会得到并行。
    • 我很抱歉造成混乱。我已经编辑了这篇文章,以明确我不是在谈论用 X 个不同的线程编写同一个文件。我只是说每个线程写一个不同的文件(但包含相同的字符串,所以我们比较苹果和苹果)
    • @marc:感谢您的澄清。
    【解决方案2】:

    是的,在 4 CPU 机器上,20 个线程绝对可以比 4 个线程更快地写入磁盘。许多实际程序的 I/O 限制比 CPU 限制更多。但是,这在很大程度上取决于您的磁盘以及其他线程在最终等待这些磁盘之前正在执行多少 CPU 工作。

    如果您的所有线程都只写入磁盘而不做任何其他事情,那么很可能 4 CPU 机器上的 1 个线程实际上是写入磁盘的最快方式。这完全取决于您拥有多少磁盘、您正在写入多少数据以及您的操作系统在 I/O 调度方面的表现如何。您的具体问题表明您希望 4 个线程都写入同一个文件。这没有多大意义,在任何实际情况下,我都无法想象这会更快。 (你必须提前分配文件,然后每个线程会 seek() 到不同的位置,最后你会在每个线程试图写一些块时敲打写头。)

    当您受网络限制时,多线程的优势要简单得多。即:在数据库服务器或网络浏览器等上等待。您正在等待多个外部资源。

    【讨论】:

      【解决方案3】:

      如果您使用的是同步 I/O,那么您的机器可以处理的每个同步 I/O 请求都应该有一个线程。如果是单轴单硬盘,则为 1(您可以读取或写入,但不能同时读取)。对于可以同时处理多个 I/O 请求的磁盘,它可以同时处理多个请求。

      换句话说,这不受 CPU 计数的限制,因为除了提交请求和等待之外,I/O 并没有真正达到 CPU。 See here for a better explanation.

      还有一大堆蠕虫,你应该在任何给定时间处理多少 I/O 请求。

      【讨论】:

      • 如果我没记错的话,即使你只有一个主轴,磁盘控制器也会尝试将 IO 请求批处理在一起,以便在磁盘的一次旋转中完成尽可能多的操作.因此,如果您有写入磁盘上完全不同角度位置的 IO 请求,我想您会从让线程同时写入它们中获得一些性能优势。否则,您将冒险在较短的操作之前同步调度较长的操作。
      【解决方案4】:

      另见Will using multiple threads with a RandomAccessFile help performance?

      更新: 我在那里添加了一个基准。

      【讨论】:

      • 感谢您指导我。不幸的是,这个问题的公认答案是错误的,除了添加我们的 cmets 之外,我们几乎无能为力。
      【解决方案5】:

      就像所有与性能相关的事情一样。

      如果您受 I/O 限制,那么添加线程对您毫无帮助。 (好的,正如Steven Sudit 指出的那样,您可能会提高性能,但会很小) 如果您不受 I/O 限制,那么添加线程可能会有所帮助

      不要试图变得聪明,但最好的发现方法是分析它,看看什么适合你的特定情况。

      编辑:基于 cmets 更新

      【讨论】:

      • 我不会对你投反对票,但正如我在回答中解释的那样,我的经历与此不同。
      • 不,我说的不是小改进。我说的是双核处理器的三到四倍。
      • 我们明确同意的一件事是,在这些问题上,实践胜过理论。对其进行编码,使其双向工作并亲自查看。当我看到改进的幅度时,我感到很惊讶。
      • Glen, re: profiling,我一直在这样做,到目前为止我发现的是 4 个线程(在 4-cpu 机器上)和 20 个线程之间的区别不是那个引人注目,但如果是 100,则降级是显着的。
      • 通过 I/O 操作添加更多线程可以让您更高效地排队并更好地隐藏延迟。
      【解决方案6】:

      Ncpu + 预期的并发 IO 活动数是我通常的数字。

      关键不是 20 个线程可以比 4 个线程更快地将单个文件写入磁盘。如果每个 cpu 只有 1 个线程,那么当您写入磁盘时,您的进程将无法使用托管正在执行文件 IO 的线程的 cpu。该 CPU 正在有效地等待文件被写入,而如果您还有一个线程,它可以在此期间使用 CPU 进行实际处理。

      【讨论】:

      • 确实如此。在操作系统级别,I/O 是异步的,因此进行同步调用仅意味着您的线程将阻塞。如果没有其他线程可供调度,CPU 利用率将会下降,并且您可能会认为您受 I/O 限制,即使您还没有达到管道的限制。
      【解决方案7】:

      如果您对该线程执行的唯一操作是写入磁盘,那么您的性能提升将微不足道,甚至有害,因为驱动程序通常针对硬盘驱动器的顺序读取进行了优化,因此您正在转换文件中的顺序写入到几个“随机”写入。

      如果在性能方面对不同的磁盘、不同的网卡或不同的数据库服务器执行 I/O,多线程只能帮助您解决 I/O 绑定问题。尽管如此,就观察到的性能而言,差异可能更大。

      例如,假设您通过网络将多个文件发送到许多不同的接收者。您仍然受网络限制,因此您的最大速度不会高于 100Mb/S,但是,如果您使用 20 个线程,那么该过程将更加公平。

      【讨论】:

      • 由于延迟,单线程不会使网卡饱和,但多线程可以。换句话说,有软上限和硬上限。
      • 我发现一个线程在饱和 1 Gb/s 网卡时没有问题。事实上,对于相对较小的消息大小,单个线程可以通过环回泵送大约 3-4 Gb/s。我还没有尝试过 10 Gb/s 网卡,但我希望在大约一个月内得到一些。
      • @Peter:延迟与带宽不同。
      猜你喜欢
      • 1970-01-01
      • 2013-03-06
      • 2014-08-22
      • 2019-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-17
      • 1970-01-01
      相关资源
      最近更新 更多