Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/359.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
令人惊讶的Java性能_Java_Performance Testing - Fatal编程技术网

令人惊讶的Java性能

令人惊讶的Java性能,java,performance-testing,Java,Performance Testing,我有这样一个压力测试仪课程: public abstract class StressTest { public static final int WARMUP_JIT_COMPILER = 10000; public interface TimedAction { void doAction(); } public static long timeAction(int numberOfTimes, TimedAction action) { ThreadMX

我有这样一个压力测试仪课程:

public abstract class StressTest {
  public static final int WARMUP_JIT_COMPILER = 10000;

  public interface TimedAction {
    void doAction();
  }

  public static long timeAction(int numberOfTimes, TimedAction action) {
    ThreadMXBean bean = ManagementFactory.getThreadMXBean();
    for (int i = 0; i < WARMUP_JIT_COMPILER; i++) {
      action.doAction();
    }
    long currentTime = bean.getCurrentThreadCpuTime();
    for (int i = 0; i < numberOfTimes; i++) {
      action.doAction();
    }
    return (bean.getCurrentThreadCpuTime() - currentTime)/1000000;
  }
}
private static boolean isPrime1(int n) { ... }
private static boolean isPrime2(int n) { ... }
private static boolean isPrime3(int n) { ... }
private static boolean isPrime4(int n) { ... }

private static final int NUMBER_OF_RUNS = 1000000;

public static void main(String[] args) {
  long primeNumberFinderTime1 = StressTest.timeAction(NUMBER_OF_RUNS, () -> {
    for (int i = 0; i < 100; i++) {
      isPrime1(i);
    }
  });
  long primeNumberFinderTime2 = StressTest.timeAction(NUMBER_OF_RUNS, () -> {
    for (int i = 0; i < 100; i++) {
      isPrime2(i);
    }
  });
  long primeNumberFinderTime3 = StressTest.timeAction(NUMBER_OF_RUNS, () -> {
    for (int i = 0; i < 100; i++) {
      isPrime3(i);
    }
  });
  long primeNumberFinderTime4 = StressTest.timeAction(NUMBER_OF_RUNS, () -> {
    for (int i = 0; i < 100; i++) {
      isPrime4(i);
    }
  });
}
class PrimeNumberFinder1 {
  @Override
  bool isPrime(i) { /* same code as in static isPrime1() */ };
}

class PrimeNumberFinder2 extends PrimeNumberFinder1 {
  @Override
  bool isPrime(i) { /* same code as in static isPrime2() */ };
}

class PrimeNumberFinder3 extends PrimeNumberFinder1 {
  @Override
  bool isPrime(i) { /* same code as in static isPrime3() */ };
}

class PrimeNumberFinder4 extends PrimeNumberFinder1 {
  @Override
  bool isPrime(i) { /* same code as in static isPrime4() */ };
}
class SomeClassWithPrimeNumberFinder {
  PrimeNumberFinder1 _pnf;

  void setPrimeNumberFinder(PrimeNumberFinder1 pnf) {
    _pnf = pnf;
  }

  void stressTest() {
    StressTest.doAction(10000000, () -> {
      for (int i = 0; i < 100; i++) {
        _pnf.isPrime(i);
      }
    });
  }
}
我有一节课是这样的:

public abstract class StressTest {
  public static final int WARMUP_JIT_COMPILER = 10000;

  public interface TimedAction {
    void doAction();
  }

  public static long timeAction(int numberOfTimes, TimedAction action) {
    ThreadMXBean bean = ManagementFactory.getThreadMXBean();
    for (int i = 0; i < WARMUP_JIT_COMPILER; i++) {
      action.doAction();
    }
    long currentTime = bean.getCurrentThreadCpuTime();
    for (int i = 0; i < numberOfTimes; i++) {
      action.doAction();
    }
    return (bean.getCurrentThreadCpuTime() - currentTime)/1000000;
  }
}
private static boolean isPrime1(int n) { ... }
private static boolean isPrime2(int n) { ... }
private static boolean isPrime3(int n) { ... }
private static boolean isPrime4(int n) { ... }

private static final int NUMBER_OF_RUNS = 1000000;

public static void main(String[] args) {
  long primeNumberFinderTime1 = StressTest.timeAction(NUMBER_OF_RUNS, () -> {
    for (int i = 0; i < 100; i++) {
      isPrime1(i);
    }
  });
  long primeNumberFinderTime2 = StressTest.timeAction(NUMBER_OF_RUNS, () -> {
    for (int i = 0; i < 100; i++) {
      isPrime2(i);
    }
  });
  long primeNumberFinderTime3 = StressTest.timeAction(NUMBER_OF_RUNS, () -> {
    for (int i = 0; i < 100; i++) {
      isPrime3(i);
    }
  });
  long primeNumberFinderTime4 = StressTest.timeAction(NUMBER_OF_RUNS, () -> {
    for (int i = 0; i < 100; i++) {
      isPrime4(i);
    }
  });
}
class PrimeNumberFinder1 {
  @Override
  bool isPrime(i) { /* same code as in static isPrime1() */ };
}

class PrimeNumberFinder2 extends PrimeNumberFinder1 {
  @Override
  bool isPrime(i) { /* same code as in static isPrime2() */ };
}

class PrimeNumberFinder3 extends PrimeNumberFinder1 {
  @Override
  bool isPrime(i) { /* same code as in static isPrime3() */ };
}

class PrimeNumberFinder4 extends PrimeNumberFinder1 {
  @Override
  bool isPrime(i) { /* same code as in static isPrime4() */ };
}
class SomeClassWithPrimeNumberFinder {
  PrimeNumberFinder1 _pnf;

  void setPrimeNumberFinder(PrimeNumberFinder1 pnf) {
    _pnf = pnf;
  }

  void stressTest() {
    StressTest.doAction(10000000, () -> {
      for (int i = 0; i < 100; i++) {
        _pnf.isPrime(i);
      }
    });
  }
}
通过此设置,
PrimeNumberFind1
的速度大约与第一次测试中的isPrime1()一样快。但是在第一次测试中,
PrimeNumberFind3
比isPrime3()慢大约200倍

如果我移动
PrimeNumberFind3
使它首先运行,那么在第一次测试中,我会得到与isPrime3()相同的时间。其余时间也有点慢(5-10%),但与
PrimeNumberFind3
不同

前3个
PrimeNumberFind
只是循环和if。没有涉及任何国家。最后一个具有创建查找列表的构造函数,但也只是一个简单的循环。如果我从构造函数中取出代码并使用数组文本创建查找列表,则时间是相同的


知道为什么会发生这种情况吗?

可能发生的情况是,最初的
iPrime
被丢弃为死代码,因为结果没有被保留/使用,所以它将运行得非常快,例如,比时钟周期快


但是,当您提供多个实现时,它必须选择调用哪个方法,因此,使用第二个方法需要更长的时间,但JIT不能内联两个以上的方法,因此第三个实现意味着测试速度大大降低,因为它需要做更多的工作来调用被丢弃的方法。

您是否尝试将结果累积到
volatile
字段中而不是将其丢弃?您还忘了向我们展示相关的代码…我尝试将结果累加到
volatile
字段中,但没有效果。我是Java新手,但volatile与线程缓存自己版本的值有关,对吗?这个程序是纯单线程的。@carlsb3rg你说得对,
volatile
与多线程相关,防止对字段的读/写进行重新排序(粗略地说)。但作为上述操作的一个副作用,它也会完全停止优化读/写操作。这就是为什么即使在单线程微基准测试中,它们也被用来累积结果的原因。@biziclop累积是关键,但我不必累积到易变字段@彼得·劳瑞收到了,不过还是谢谢你。我相信
volatile
以后会很有用;)@约翰伯林格虽然最好的办法是修改测试,但我认为他得到的结果值得解释对静态版本(特别是isPrime3())运行速度快得不可思议,因为它包含的所有内容都是
返回(n==2 | | n==3…
,用于100以下的所有素数。当我看数字时,JIT内联两个方法非常有意义。现在我只需要弄清楚为什么一个方法在n<2时返回false,在n<4时返回true,在n%2==0时返回false,以及一个循环在3->sqrt(n)中尝试每个奇数比所有素数小于100的just or's n的返回语句快10%。@carlsb3rg内联也可能是这里的关键。长链的
可能会使您的方法超出内联的指令限制,而短循环的处理可能会更好。我建议你看看,它可能会派上用场。非常感谢!我将查看jitwatch,看看是否可以进行一些位操作。