在java中执行IO操作的最佳线程数是多少?

在Goetz的“实践中的Java并发”中,在第101页的脚注中,他写道:“对于这样的计算问题,没有I / O并且不访问共享数据,Ncpu或Ncpu + 1线程产生最佳吞吐量;更multithreading不帮助,实际上可能会降低性能…“

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

不过,我想知道:在4-cpu机器上,20个线程可以将1000个单独的文件写入磁盘,而不是4个线程吗?

在实践中,I / O绑定的应用程序仍然可以从multithreading中获益,因为并行读取或写入一些文件要快得多。 特别是在整体吞吐量受网络延迟影响的情况下。 但也有一种情况是,一个线程可以处理它读取的最后一个东西,而另一个线程忙于读取,从而允许更高的CPU利用率。

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

是的,20个线程绝对能够比4 CPU机器上的4个线程更快地写入磁盘。 许多实际程序的I / O限制超过了CPU绑定。 但是,它在很大程度上取决于您的磁盘以及其他线程正在执行的CPU工作量,然后它们最终会在这些磁盘上等待。

如果你的所有线程都只是写入磁盘并且什么都不做,那么4 CPU机器上的1个线程实际上是写入磁盘的最快方式。 它完全取决于您拥有的磁盘数量,您正在编写的数据量以及您的操作系统在I / O调度方面的优势。 您的具体问题表明您希望4个线程都写入同一个文件。 这没有多大意义,在任何实际情况下,我都无法想象这会更快。 (你必须提前分配文件,然后每个线程都会寻找()到不同的位置,并且当每个线程试图写一些块时,你最终只是颠倒了写头。)

当您受网络约束时,multithreading的优势更加简单。 即:在数据库服务器或Web浏览器等上等待。 你在等待多个外部资源。

就像所有与性能相关的东西一样。

如果你受I / O约束,那么添加线程根本不会帮助你。 (好吧,正如Steven Sudit指出的那样,你可能会提高性能,但它会很小)如果你不是I / O绑定那么添加线程可能会有所帮助

不要试图变得聪明,但最好的方法是找出它并查看哪些适合您的特定情况。

编辑:根据评论更新

另请参阅使用具有RandomAccessFile帮助性能的多个线程吗?

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

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

换句话说,这不受CPU数量的限制,因为I / O除了提交请求和等待之外并没有真正击中CPU。 请参阅此处以获得更好的解释。

还有其他一些蠕虫可以在任何给定时间内有多少I / O请求。

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

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

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

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

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