1

我知道有很多因素会影响Java程序的运行时间。我试图消除其中的一些,其中包括:什么可能会导致并行Java程序运行时间差异很大?

  • 预热运行被考虑并且不计算在内。
  • System.gc()在任何两次运行之间调用。

但我发现数据仍然变化很大。下面是当使用10个线程的例子:

157th run 
0 run time: 9106171 
1 run time: 9084652 
2 run time: 8990820 
3 run time: 8989474 
5 run time: 9062850 
4 run time: 9302010 
9 run time: 9454475 
8 run time: 9506585 
7 run time: 9494990 
6 run time: 9491779 
total time: 31 ms 

158th run 
2 run time: 14754858 
5 run time: 14865035 
0 run time: 15759180 
1 run time: 15988056 
3 run time: 16660592 
8 run time: 16340240 
9 run time: 16544479 
6 run time: 17280122 
7 run time: 17249778 
4 run time: 18026322 
total time: 19 ms 

我发现多数奔跑,他们把像17〜20毫秒,但对于< 5%运行时,他们采取了类似25〜31毫秒。更有趣的是,在后面的情况下,每个线程的运行时间甚至更短,更短

该程序的主线程只有start()join()的线程,并且没有更多的工作要做。

任何人都可以提供一些想法/提示?

+0

这些线程究竟在做什么? –

+0

第一次猜测:JIT热身。第二个猜测:GC(随着对象的积累,并被扫除)。你已经涵盖了这些。建议:1)剖析应用程序,2)观察运行时的堆行为 – paulsm4

+0

@DavidSchwartz基本上,每个线程处理一个字符串段并生成一个树数据结构。 – JackWM

回答

1

假设第157次运行,所有线程都在一个内核上运行。瓶颈只是让他们像时尚一样排队等待对方。每个人的跑步都很快,因为他们对内存资源进行了独占统治,但总体来说很慢,因为他们都排队等待轮到他们。

假设第158次运行分布在多个内核中。所有人都会立即竞争内存/缓存资源,因此每个线程都需要更长的时间。但是因为他们都在同一时间工作,所以整个过程更快完成。

为了测试这个假设,在运行之间重用一个线程池,并手动设置它们的亲和性。

这只是一个可能的解释,有可能是其他因素,它都是非确定性的。例如,您的操作系统可能同时安排了一些其他程序(例如,cron作业)。

+0

你是什么意思“但总体来说很慢”?主线程除了创建/销毁线程外没有做任何事情。 – JackWM

+0

处理器亲和度/操作系统调度可能是相关的 - Daniel Kinsman提出的很好的建议!关于“剖析”,有很多资源。 JConsole是一个很好的开始。请参阅此链接:http://www.infoq.com/articles/java-profiling-with-open-source – paulsm4

+0

@JackWM主线程坐在那里,等待所有其他人完成。这就是'join'的作用。 –

3

我注意到你正在启动和停止线程。由于测试非常短,这些线程只有时间分配给一个(或少量)cpus排列。这种安排可能意味着更多的线程同时运行,但是使用超线程技术,都会使用核心的cpus。当发生这种情况时,每个线程都会变慢(因为它必须共享一个内核,缓存等),但吞吐量会随着线程上下文切换的减少和内核的更高效使用而增加。在另一种安排中,每个内核可能只有一个CPU繁忙,这意味着每个线程更快,但总运行时间更长。

我会尝试使用一个ExecutorService,使用与您有cpus(或一些多个)相同的数量任务并重新使用这些线程。这会让你在运行之间更加一致,操作系统将有时间以更有效的方式放置你的线程。

我写了一个库,可以让你分配线程到不同的CPU布局。例如共享或不共享核心。 https://github.com/peter-lawrey/Java-Thread-Affinity

+0

是的 - 尝试将线程绑定到内核以提高性能,但是随后使用开始/连接:(( –

+0

)当有少量关键线程存在很长一段时间时,关联有助于帮助减少不可预测性在测试中也是如此。 –

相关问题