我已经实现了一个向服务器发送请求的客户端应用程序。它的工作方式可以非常简单地描述。我指定了多个线程。每个线程都会重复向服务器发送请求并等待答案。
我已经绘制了不同数量线程的客户端总吞吐量。虚拟客户端的数量并不重要,我感兴趣的是图表最右侧的最大饱和性能。
我很惊讶,因为我没想到性能会随着线程数量的增加而变化。事实上,大部分处理器时间都花在了 Java 中的阻塞 i/o(阻塞套接字)上,因为客户端与服务器之间的通信有 1 毫秒的延迟,并且客户端运行在 8 核机器上。
我在网上寻找解决方案,这个答案在 Quora似乎意味着阻塞 i/o 的等待时间可以安排用于其他任务。是真的吗,专门针对 Java 阻塞套接字?在这种情况下,为什么我不能随线程数量进行线性缩放?
如果这很重要,我会在云中运行此应用程序。另外,这是一个更大的应用程序的一部分,但我已将该组件确定为整个设置的瓶颈。
最佳答案
I have looked for solutions online, this answer on Quora seems to imply that the waiting time for blocking i/o can be scheduled to use for other tasks. Is is true, specifically for Java blocking sockets ?
常规 Java 线程一对一映射到操作系统级线程。它们是等价的。所以,是的,Java 确实如此,事实上,其他所有语言也是如此。除非它使用 Green Threads或非阻塞 IO。
In that case, why don't I get linear scaling with the number of threads ?
从CPU的角度思考你在做什么。 CPU 执行代价高昂的上下文切换并允许某些线程运行。该线程在很短的时间内使用 CPU 来准备网络调用,然后它会阻塞很长时间(对于工作在 3GHz 的 CPU 来说,毫秒是相当长的)。
因此,在需要另一次上下文切换之前,每个线程只执行一小部分工作。这意味着 CPU 的大量时间都浪费在上下文切换上,而不是做有用的工作。
将其与执行 CPU-bound 的线程进行对比任务。上下文切换需要相同的时间。但是,当允许运行受 CPU 限制的任务时,它会设法长时间利用 CPU,相比之下,上下文切换的成本会更低。这会提高总体 CPU 利用率。
因此,一方面,您会看到每个新线程的速率更高,因为您实际上执行了更多并发 I/O 操作。另一方面,每个新线程都会增加成本。所以每个额外线程的边际效益每次都会小一点。如果您继续添加线程,在某些时候您甚至会达到每个新线程的速率都会下降的程度。
关于java - 多线程客户端网络应用程序的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53601767/