1

好的。我对微基准测试的计算有误。如果您没有多余的时间,请不要阅读。

代替

double[] my_array=new array[1000000];double blabla=0;
for(int i=0;i<1000000;i++)
{
  my_array[i]=Math.sqrt(i);//init
}

for(int i=0;i<1000000;i++)
{
  blabla+=my_array[i];//array access time is 3.7ms per 1M operation
}

我用了

public final static class my_class
{
 public static double element=0;
 my_class(double elementz)
 {
 element=elementz;
 }
}

my_class[] class_z=new my_class[1000000];
for(int i=0;i<1000000;i++)
{
class_z[i]=new my_class(Math.sqrt(i)); //instantiating array elements for later use(random-access)
}

double blabla=0;

for(int i=0;i<1000000;i++)
{
blabla+=class_z[i].element; // array access time 2.7 ms per 1M operations.
}
}

每 1M 循环迭代的循环开销接近 0.5 毫秒(使用此偏移量)。

类数组的元素访问时间比原始数组的低 %25。问题:你知道有什么其他方法可以降低随机访问时间吗?intel 2Ghz 单核 java -eclipse

4

3 回答 3

2

再次查看您的代码,我可以看到在第一个循环中您添加了 1m 个不同的元素。在第二个示例中,您将相同的static元素添加 1m 次。


微基准测试的一个常见问题是您执行测试的顺序会影响结果。

例如,如果您有两个循环,则第一个循环最初不会编译为本机代码。然而一段时间后,整个方法将被编译并且循环将运行得更快。

然后你运行第二个循环,发现它是

  • 更快,因为它从一开始就进行了优化。(对于简单的循环)
  • 慢得多,因为它在没有任何运行时指标的情况下进行了优化。(对于复杂的循环)

您需要将每个循环放在单独的方法中,并交替运行测试多次以获得可重现的结果。


在您的第一种情况下,循环在运行一段时间后才会优化。在第二种情况下,您的循环很可能在启动时已经编译。

于 2012-06-28T15:35:57.210 回答
1

区别很容易解释:

  • 原始数组的内存占用为 1M * 8 字节 = 8MB。
  • 类数组的内存占用为 1M * 4 字节 = 4MB,都指向同一个实例(假设 32 位 VM 或压缩 refs 64 位 VM)。

将不同的对象放入您的类数组中,您会看到原始数组表现得更好。您目前正在将橙子与苹果进行比较。

于 2012-06-28T15:52:44.457 回答
0

您的基准测试和上述评估存在几个问题。首先,您的代码不会如图所示编译。其次,您的基准测试时间(即几毫秒)太短了,无法在当今的高速处理器中提供任何统计价值。第三,您将苹果与橙子进行比较(如上所述)。也就是说,您正在为两个完全不同的用例计时:一个静态变量和一百万个变量。

我修复了您的代码并在 i7-2620m 上运行了几次,重复 10,000 x 1,000,000 次。所有结果都在 +/- 1% 以内,这对于本次讨论来说已经足够了。然后,为了比较它们的性能,我选择了所有这些运行中最快的。

上面,您声称第二个用例比第一个用例“低 25%”。这是非常不准确的。

为了进行“静态”与“可变”性能比较,我将第一个基准更改为添加第 999,999 个平方根,就像第二个基准所做的那样。有利于第二个用例的差异仅约为 4.63%。

为了进行数组访问性能比较,我将第二个用例更改为“非静态”变量。第一个用例(原始数组访问)的差异约为 68.2%,这意味着第一种方式比第二种方式快得多。

(由于我从事绩效测量和评估超过 25 年,请随时向我询问有关微基准测试的更多信息。)

于 2013-01-25T21:28:45.527 回答