【问题标题】:Java Performance measurementJava 性能测量
【发布时间】:2011-01-27 07:38:31
【问题描述】:

我正在对我的类之间的 Java 性能进行比较,并想知道是否有某种 Java 性能框架可以使编写性能测量代码更容易?

也就是说,我现在正在做的是尝试衡量与使用 AtomicInteger 作为我的“同步器”相比,使用 PseudoRandomUsingSynch.nextInt() 中的“同步”方法会产生什么影响。

所以我试图测量使用 3 个线程访问同步方法循环生成 10000 次随机整数需要多长时间。

我确信有更好的方法来做到这一点。你能启发我吗? :)

public static void main( String [] args ) throws InterruptedException, ExecutionException {
    PseudoRandomUsingSynch rand1 = new PseudoRandomUsingSynch((int)System.currentTimeMillis());
    int n = 3;
    ExecutorService execService = Executors.newFixedThreadPool(n);

    long timeBefore = System.currentTimeMillis();
    for(int idx=0; idx<100000; ++idx) {
        Future<Integer> future = execService.submit(rand1);
        Future<Integer> future1 = execService.submit(rand1);
        Future<Integer> future2 = execService.submit(rand1);

        int random1 = future.get();
        int random2 = future1.get();
        int random3 = future2.get();

    }
    long timeAfter = System.currentTimeMillis();
    long elapsed = timeAfter - timeBefore;
    out.println("elapsed:" + elapsed);
}

班级

public class PseudoRandomUsingSynch implements Callable<Integer> {
private int seed;

public PseudoRandomUsingSynch(int s) { seed = s; }

public synchronized int nextInt(int n) {
    byte [] s = DonsUtil.intToByteArray(seed);
    SecureRandom secureRandom = new SecureRandom(s);
    return ( secureRandom.nextInt() % n );
}

@Override
public Integer call() throws Exception {
    return nextInt((int)System.currentTimeMillis());
}
}

问候

【问题讨论】:

  • “Java 性能框架使编写性能测量代码更容易”?什么这么难?你能解释一下你希望这个框架为你做什么吗?
  • 到目前为止,我必须自己编写循环,测量经过的时间。也许有了框架,我不必做那么多的手动编码。
  • @S.Lott:我不是问这个问题的人,但“跳出框框思考”从不伤害任何人。比如说,我可以想象一个框架,它可以通过对两种情况运行 100 次来进行统计性能分析,然后只保留 80% 的值在中值附近,以丢弃异常值。有什么难的呢?你真的想重新发明那个轮子吗?我当然可以写,但如果有一个我可以简单下载的知名工具/API/框架,我会喜欢它...
  • @WizardOfOdds。统计数据,是的:很明显,有人会用一个包来做到这一点。收集统计数据(即通用循环)也许——但它是一行代码。然而,该示例的其余部分不能轻易简化。这就是我要求澄清的原因。我讨厌假设——假设通常是错误的。我没有假设,而是问。
  • 有一个名为 ScalaMeter 的 Scala 和 Java 微基准测试框架,您可能想了解一下。网站上的入门指南也提供了很多有用的见解。

标签: java performance multithreading


【解决方案1】:

忽略微基准对您的情况是否有用的问题(Stephen C 的观点非常有效),我会指出:

首先,不要听那些说“没那么难”的人。是的,在使用 JIT 编译的虚拟机上进行微基准测试很困难。实际上很难从微基准中得到有意义和有用的数字,任何声称这不难的人要么是超级天才,要么是做错了。 :)

其次,是的,周围有一些这样的框架。值得一看(认为它处于非常早期的预发布阶段)是Caliper,作者是 Google 的 Kevin Bourrillion 和 Jesse Wilson。从早期的几次观察中看起来确实令人印象深刻。

【讨论】:

  • +1 - 那些说微基准测试很容易的人......是错误的。这也不只是在 Java 中。
  • Caliper +1 - 我自己用过这个,效果很好
  • 很好的解释
【解决方案2】:

更多微基准测试建议 - 微基准测试很少告诉您真正需要知道的内容......真正的应用程序运行速度有多快。

在您的情况下,我想您正试图弄清楚 您的应用程序 使用 Atomic 对象是否会比使用同步对象更好......反之亦然。真正的答案是,它很可能取决于微基准无法衡量的因素。诸如争用的概率、锁的持有时间、线程和处理器的数量,以及使原子更新成为​​可行解决方案所需的额外算法工作量。

EDIT - 回答这个问题。

那么有没有一种方法可以衡量所有这些争用概率、锁定持有时间等?

理论上是的。一旦您实现了整个应用程序,就可以对其进行检测以测量这些内容。但这也不能给你答案,因为没有一个预测模型可以插入这些数字来给出答案。而且,那时你已经实现了应用程序。

但我的意思并不是衡量这些因素可以让您预测性能。 (它没有!)相反,微基准允许您预测性能任何一个

实际上,最好的方法是根据您的直觉来实现应用程序,然后使用 profiling 作为找出真正性能问题所在的基础。

【讨论】:

  • 那么有没有一种方法可以测量所有这些争用概率、锁定持有时间等?
【解决方案3】:

OpenJDK 开发了一个名为 JMH 的基准测试工具:

http://openjdk.java.net/projects/code-tools/jmh/

这提供了一个非常容易设置的框架,并且有几个示例展示了如何使用它。

http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/

没有什么可以阻止您编写错误的基准测试,但它们在消除不明显的错误(例如线程之间的错误共享、防止死代码消除等)方面做得很好。

【讨论】:

    【解决方案4】:

    这些人设计了一个很好的 JVM 测量方法,这样您就不会用虚假数字欺骗自己,然后将其发布为 Python 脚本,以便您可以重用他们的聪明才智 -

    Statistically Rigorous Java Performance Evaluation (pdf paper)

    【讨论】:

    • 虽然这个答案并没有说明太多,但链接的论文非常好,值得一读(不仅适用于 Java,还适用于任何分析)。
    【解决方案5】:

    您可能希望将循环移动到任务中。因为它是你刚刚启动所有线程,几乎立即你回到单线程。

    通常的微基准测试建议:允许一些热身。与平均值一样,偏差也很有趣。使用System.nanoTime 而不是System.currentTimeMillis

    这个问题的具体问题是线程之间的斗争程度。由于有大量竞争线程,cas 循环可以执行浪费的工作。创建SecureRandom 可能很昂贵,System.currentTimeMillis 可能在较小程度上。如果使用正确,我相信SecureRandom 应该已经是线程安全的了。

    【讨论】:

      【解决方案6】:

      简而言之,您是在寻找“Java 单元性能测试工具”吗?

      使用JUnitPerf

      更新:对于尚不清楚的情况:它还支持并发(多线程)测试。这是上述链接的“LoadTest”一章的摘录,其中包括一个代码示例:

      例如,创建一个负载测试 每个用户 10 个并发用户 运行 ExampleTestCase.testOneSecondResponse() 方法进行 20 次迭代,并且使用 1 添加之间的第二次延迟 用户,使用:

      int users = 10;
      int iterations = 20;
      Timer timer = new ConstantTimer(1000);
      Test testCase = new ExampleTestCase("testOneSecondResponse");
      Test repeatedTest = new RepeatedTest(testCase, iterations);
      Test loadTest = new LoadTest(repeatedTest, users, timer);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-17
        • 2011-12-20
        • 1970-01-01
        • 1970-01-01
        • 2019-10-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多