多线程客户端网络应用的性能
Performance of Multi-Threaded Client Network Application
我已经实现了一个向服务器发送请求的客户端应用程序。它的工作方式可以非常简单地描述。我指定了一些线程。每个线程都重复向服务器发送请求并等待答复。
我绘制了不同线程数的客户端总吞吐量。虚拟客户端的数量并不重要,我对图表最右侧的最大饱和性能感兴趣。
我很惊讶,因为我没想到性能会随着线程数的增加而增加。事实上,大部分处理器时间都花在阻塞 i/o in Java(阻塞套接字)上,因为客户端-服务器通信有 1ms 的延迟,而客户端是 运行 在 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 线程一对一映射到 OS 级线程。他们是等价的。所以是的,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 操作。另一方面,每个新线程都会增加成本。所以每增加一个线程的边际收益每次都会变小一点。如果你继续添加线程,在某个时候你甚至会达到一个速度会随着每个新线程而下降的点。
我已经实现了一个向服务器发送请求的客户端应用程序。它的工作方式可以非常简单地描述。我指定了一些线程。每个线程都重复向服务器发送请求并等待答复。
我绘制了不同线程数的客户端总吞吐量。虚拟客户端的数量并不重要,我对图表最右侧的最大饱和性能感兴趣。
我很惊讶,因为我没想到性能会随着线程数的增加而增加。事实上,大部分处理器时间都花在阻塞 i/o in Java(阻塞套接字)上,因为客户端-服务器通信有 1ms 的延迟,而客户端是 运行 在 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 线程一对一映射到 OS 级线程。他们是等价的。所以是的,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 操作。另一方面,每个新线程都会增加成本。所以每增加一个线程的边际收益每次都会变小一点。如果你继续添加线程,在某个时候你甚至会达到一个速度会随着每个新线程而下降的点。