1

我知道有很多因素会影响 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()没有更多的工作要做。

谁能提供一些想法/提示?

4

2 回答 2

3

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

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

我编写了一个库,它允许您将线程分配给不同的 cpu 布局。例如共享或不共享内核。https://github.com/peter-lawrey/Java-Thread-Affinity

于 2012-09-04T07:18:49.823 回答
1

假设在第 157 次运行中,所有线程都在一个核心上运行。瓶颈只是他们像排队一样等待对方。每个人的运行速度都很快,因为他们对内存资源拥有唯一的控制权,但总的来说,速度很慢,因为他们都排着队等待轮到自己。

假设第 158 次运行分布在多个内核上。所有人都会同时竞争内存/缓存资源,因此每个线程单独花费​​的时间更长。但是因为他们都在同一时间工作,所以这个过程通常完成得更快。

为了检验这个假设,在运行之间重用一个线程池,并以一种或另一种方式手动设置它们的亲和性。

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

于 2012-09-04T06:12:35.053 回答