如何让几十个线程同时 运行
How to get dozens of thread to run simultaneously
我们目前有一个将消息写入服务器的程序。对于容量测试,我们 运行 同一程序的许多实例,这很尴尬。我正在开发一个程序,该程序会创建多个线程来编写消息。
但是,问题是线程发送消息的速度不均匀。相反,有些人甚至在其他人开始之前就完成了发送。请注意,所有线程大约在同一时间启动,在一个循环中,并发送相同的消息。
对此有什么可以做的吗?问题的原因可能是什么?
编辑:我是新手,但有人告诉我,当 运行 程序的单独实例(与多线程解决方案相反)时,这不是问题。
Is there anything that can be done about this? What might be the cause of the problem?
基本上,问题是您的系统存在瓶颈:
您拥有的内核数量限制了一次实际可以 运行 的线程数量1。
OS 和网络限制了您的系统可以发送的网络流量。
OS 和磁盘硬件限制了系统可以处理的文件 I/O 流量(如果这与此处相关)
您的多线程应用程序可能存在内部并发瓶颈;例如等待互斥体访问共享数据结构的线程。
也会出现瓶颈,代表您的服务器接受消息的能力,尤其是在负载下。
(一些性能监控会为您提供一些线索,让您了解以上哪一项或其他可能对您的情况最重要。在某些情况下,您可以解决这些问题...)
面对瓶颈,您的某些 Java 线程将不可避免地 运行 比其他线程慢。对于 that,您无能为力。这是因为 Java 线程调度器没有实现 "fair" 调度。更广泛地说,网络和磁盘 I/O 系统也没有。 (它们针对公平以外的其他方面进行了优化。)
但这是给你的(修辞性的)问题。某些线程比其他线程花费更长的时间真的很重要吗?这不等同于某些现实生活中的客户端比其他客户端慢(出于某种原因)吗?对您来说重要的是您的服务器在面临高负载时的行为;即它可以承受的请求速率,以及超过该速率时会发生什么。
现在您的问题可能是您创建的线程太多了。 (有些人错误地认为 N 个线程可以使您获得 N 倍的加速!)创建太多线程会浪费资源2,并且由于二次效应会导致性能下降。如果您有大量任务要执行,更好的方法是使用 ExecutorService
和有界线程池。将任务放入队列,让服务负责创建线程等。
I've been told that this isn't a problem when running separate instances of the program (as opposed to the multi-thread solution).
我认为你 "told" 是错误的。如果您同时启动 N 个单线程应用程序,您很可能会看到 甚至更多 执行时间的变化。 (而且吞吐量会更差,因为你现在有 N 次 JVM 预热的开销,而不是一次。)
1 - 例如,如果您有 8 个物理内核或超线程,则您的应用程序一次只能使用 8 个线程 运行ning。再多一点在物理上是不可能的。如果有超过 8 个线程 运行nable,一些线程将等待调度。
2 - 每个线程都将内存用于其堆栈及其引用的对象。增加的内存占用会增加 GC 开销,影响内存缓存性能。如果你没有足够的物理内存,它会导致过多的分页。
我们目前有一个将消息写入服务器的程序。对于容量测试,我们 运行 同一程序的许多实例,这很尴尬。我正在开发一个程序,该程序会创建多个线程来编写消息。
但是,问题是线程发送消息的速度不均匀。相反,有些人甚至在其他人开始之前就完成了发送。请注意,所有线程大约在同一时间启动,在一个循环中,并发送相同的消息。
对此有什么可以做的吗?问题的原因可能是什么?
编辑:我是新手,但有人告诉我,当 运行 程序的单独实例(与多线程解决方案相反)时,这不是问题。
Is there anything that can be done about this? What might be the cause of the problem?
基本上,问题是您的系统存在瓶颈:
您拥有的内核数量限制了一次实际可以 运行 的线程数量1。
OS 和网络限制了您的系统可以发送的网络流量。
OS 和磁盘硬件限制了系统可以处理的文件 I/O 流量(如果这与此处相关)
您的多线程应用程序可能存在内部并发瓶颈;例如等待互斥体访问共享数据结构的线程。
也会出现瓶颈,代表您的服务器接受消息的能力,尤其是在负载下。
(一些性能监控会为您提供一些线索,让您了解以上哪一项或其他可能对您的情况最重要。在某些情况下,您可以解决这些问题...)
面对瓶颈,您的某些 Java 线程将不可避免地 运行 比其他线程慢。对于 that,您无能为力。这是因为 Java 线程调度器没有实现 "fair" 调度。更广泛地说,网络和磁盘 I/O 系统也没有。 (它们针对公平以外的其他方面进行了优化。)
但这是给你的(修辞性的)问题。某些线程比其他线程花费更长的时间真的很重要吗?这不等同于某些现实生活中的客户端比其他客户端慢(出于某种原因)吗?对您来说重要的是您的服务器在面临高负载时的行为;即它可以承受的请求速率,以及超过该速率时会发生什么。
现在您的问题可能是您创建的线程太多了。 (有些人错误地认为 N 个线程可以使您获得 N 倍的加速!)创建太多线程会浪费资源2,并且由于二次效应会导致性能下降。如果您有大量任务要执行,更好的方法是使用 ExecutorService
和有界线程池。将任务放入队列,让服务负责创建线程等。
I've been told that this isn't a problem when running separate instances of the program (as opposed to the multi-thread solution).
我认为你 "told" 是错误的。如果您同时启动 N 个单线程应用程序,您很可能会看到 甚至更多 执行时间的变化。 (而且吞吐量会更差,因为你现在有 N 次 JVM 预热的开销,而不是一次。)
1 - 例如,如果您有 8 个物理内核或超线程,则您的应用程序一次只能使用 8 个线程 运行ning。再多一点在物理上是不可能的。如果有超过 8 个线程 运行nable,一些线程将等待调度。
2 - 每个线程都将内存用于其堆栈及其引用的对象。增加的内存占用会增加 GC 开销,影响内存缓存性能。如果你没有足够的物理内存,它会导致过多的分页。