【发布时间】:2018-04-11 00:12:45
【问题描述】:
我有一个类似这样的程序
public class Test implements Runnable
{
public int local_counter
public static int global_counter
// Barrier waits for as many threads as we launch + main thread
public static CyclicBarrier thread_barrier = new CyclicBarrier (n_threads + 1);
/* Constructors etc. */
public void run()
{
for (int i=0; i<100; i++)
{
thread_barrier.await();
local_counter = 0;
for(int j=0 ; j = 20 ; j++)
local_counter++;
thread_barrier.await();
}
}
public void main()
{
/* Create and launch some threads, stored on thread_array */
for(int i=0 ; i<100 ; i++)
{
thread_barrier.await();
thread_barrier.await();
for (int t=1; t<thread_array.length; t++)
{
global_counter += thread_array[t].local_counter;
}
}
}
}
基本上,我有几个线程有自己的本地计数器,我正在这样做(循环)
|----| | |----|
|main| | |pool|
|----| | |----|
|
-------------------------------------------------------
barrier (get local counters before they're overwritten)
-------------------------------------------------------
|
| 1. reset local counter
| 2. do some computations
| involving local counter
|
-------------------------------------------------------
barrier (synchronize all threads)
-------------------------------------------------------
|
1. update global counter |
using each thread's |
local counter |
这一切都应该很好,但事实证明这并不能很好地扩展。在 16 个物理节点的集群上,6-8 个线程后的加速可以忽略不计,所以我必须摆脱其中一个等待。我尝试过使用 CyclicBarrier,它的扩展性非常好,Semaphores,它做的一样多,还有一个自定义库 (jbarrier),它可以很好地工作,直到线程数多于物理内核,此时它的性能比顺序版本差。但是如果不停止所有线程两次,我就是想不出一种方法。
编辑:虽然我感谢您对我的程序中任何其他可能的瓶颈的所有见解,但我正在寻找有关此特定问题的答案。如果需要,我可以提供更具体的示例
【问题讨论】:
-
您要解决的问题有多复杂? CountDownLatch 之类的东西是否会有所帮助,因为它可能会降低解决方案的复杂性?
-
@HarisNadeem 问题是 CountDownLatch 被设计为使用一次,而我在一个循环中连续使用这个 Barrier - 我想我可以在每个循环中创建一个新的 CountDownLatch,我没有尝试过,但我没有认为它会是有效的
-
是的,每次都创建一个新的效率不高。如果您不介意,我对问题的大小和硬件有一些疑问。您尝试解决的问题可能是内存密集型?如果是这样,增加线程只会增加内存负载,并且会减慢其他线程可用的内存。线程中是否可能涉及IO?如果是这样,这可能是一个瓶颈,增加线程超过某个点可能无法解决。
-
这对我来说看起来像是一个标准的生产者-消费者问题,为什么线程不能独立计算它们的结果并用它们的 id 将它们放入队列中。随后主要可以消耗它们吗?我假设消费者比生产者快得多。
-
你能分享一个更详细的例子吗? (最好能看到源代码或可运行的示例。)
标签: java concurrency parallel-processing synchronization java.util.concurrent