答案 0 :(得分:6)
您似乎不需要工作人员之间的任何同步。也许你应该考虑使用Java 7中提供的ForkJoin框架,以及一个单独的库。一些链接:
答案 1 :(得分:3)
更新:V6 - 忙碌等待,主线程也正常工作
V5的明显改进(繁忙等待7个工作线程中的工作,忙等待主线程完成)似乎再次将工作分成7 + 1个部分并让主线程与另一个同时处理一个部分工作线程(而不是忙等待),随后忙 - 等待所有其他线程的工作项的完成。这将使用第8个处理器(在示例的8核配置中)并将其周期添加到可用的计算资源池。
这实际上是直截了当的。结果确实再次稍好一些:
blocksize | system | user | cycles/sec
256k 1.0% 98% 1.39
64k 1.0% 98% 6.8
16k 1.0% 98% 50.4
4096 1.0% 98% 372
1024 1.0% 98% 1317
256 1.0% 98% 3546
64 1.5% 98% 9091
16 2.0% 98% 16949
所以这似乎代表了迄今为止最好的解决方案。
答案 2 :(得分:1)
更新:V5 - 在所有线程中忙碌等待(到目前为止似乎是最佳的)
由于所有内核都专门用于此任务,因此尝试简单地消除所有复杂的同步构造并在所有线程中的每个同步点执行忙等待似乎是值得的。结果大大超过了所有其他方法。
设置如下:从上面的V4开始(CyclicBarrier + Busy Wait)。 用AtomicInteger替换CyclicBarrier,主线程在每个周期重置为零。完成其工作的每个工作线程Runnable将原子整数递增1。主线程忙等待:
while( true ) {
// busy-wait for threads to complete their work
if( atomicInt.get() >= workerThreadCount ) break;
}
而不是8,只启动了7个工作线程(因为所有线程,包括主线程,现在几乎完全加载了一个核心)。 结果如下:
blocksize | system | user | cycles/sec
256k 1.0% 98% 1.36
64k 1.0% 98% 6.8
16k 1.0% 98% 44.6
4096 1.0% 98% 354
1024 1.0% 98% 1189
256 1.0% 98% 3222
64 1.5% 98% 8333
16 2.0% 98% 16129
在工作线程中使用wait / notify会降低吞吐量 大约1/3的解决方案。
答案 3 :(得分:1)
我也想知道你是否可以尝试超过8个线程。如果你的CPU支持HyperThreading(至少在理论上)你可以每个核心挤出2个线程,看看它是什么。
答案 4 :(得分:1)
更新:V7 - 忙碌等待恢复等待/通知
在玩了一些V6之后,事实证明忙碌等待在分析时稍微模糊了应用程序的真实热点。此外,即使没有处理任何工作项,系统上的风扇也会继续过载。因此,进一步的改进是忙于等待固定时间(例如,大约2毫秒)的工作项,然后恢复到“更好”的wait()/ notify()组合。工作线程只是通过一个原子布尔值将它们当前的等待模式发布到主线程,该原子布尔值指示它们是否正在忙等待(因此只需要设置一个工作项)或者是否期望调用notify()因为它们在等待()。
另一个变得相当直接的改进是让已完成主要工作项的线程在等待其他线程完成其主要工作项时重复调用客户端提供的回调。这样,等待时间(因为线程必然会得到稍微不同的工作负载而发生)不需要完全丢失给应用程序。
对于遇到类似用例的其他用户,我仍然非常感兴趣。
答案 5 :(得分:1)
刚刚碰到这个帖子,即使它已经快一年了,让我指出几个月前我们在波恩大学开发的“jbarrier”库:
http://net.cs.uni-bonn.de/wg/cs/applications/jbarrier/
屏障包完全针对工作线程数< =核心数的情况。该软件包基于忙等待,它不仅支持屏障操作,还支持全局缩减,除了中央屏障外,它还提供了树形结构的屏障,可以进一步并行化同步/缩减部分。