【问题标题】:Java Exceptions Loops and Deprecation (or is it a URLEncoding thing?)Java 异常循环和弃用(或者它是 URLEncoding 的东西?)
【发布时间】:2009-05-25 02:30:41
【问题描述】:

我刚刚写了一个关于我如何达到这一点的完整简介,但我认为发布代码并保留它更容易:)

据我所知,test3() 的性能应该与 test1() 相同 - 唯一的区别是捕获异常的位置(在 test1() 的调用方法内,在 test3 的被调用方法内())

为什么 test3() 经常需要在 test1() 和 test2() 之间的某个时间来完成?

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

public class Test {

    public static void main(String[] args) {
        warmup(); 
        test1(2500000); // Exception caught inside the loop
        test2(2500000); // Exception caught outside the loop
        test3(2500000); // Exception caught "inside" the loop, but in the URLEncoder.encode() method
    }

    private static void warmup() {
        // Let URLEncoder do whatever startup it needs before we hit it
        String encoding = System.getProperty("file.encoding");
        try {
            URLEncoder.encode("ignore", encoding);
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private static void test1(int count) {
        String encoding = System.getProperty("file.encoding");
        long start = System.currentTimeMillis();
        for (int i = 0; i < count; i++) {
            try {
                URLEncoder.encode("test 1 " + i, encoding);
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("Performed " + count + " encodings trying to catch each in " + (end - start) + "ms");
    }

    private static void test2(int count) {
        String encoding = System.getProperty("file.encoding");
        long start = System.currentTimeMillis();
        try {
            for (int i = 0; i < count; i++) {
                URLEncoder.encode("test 2" + i, encoding);
            }
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("Performed " + count + " encodings trying to catch all in " + (end - start) + "ms");
    }

    private static void test3(int count) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < count; i++) {
            URLEncoder.encode("test 3 " + i);
        }
        long end = System.currentTimeMillis();
        System.out.println("Performed " + count + " encodings with a deprecated method in " + (end - start) + "ms");
    }

}

运行它会给我(Windows XP 上的 JDK 1.6.0_13)输出:

Performed 2500000 encodings trying to catch each in 4906ms
Performed 2500000 encodings trying to catch all in 2454ms
Performed 2500000 encodings with a deprecated method in 2953ms

所以,响应非常接近(我们正在谈论一些无关紧要的微不足道的事情),但是我很好奇!

稍后...

人们认为 JVM 优化会阻碍这一点 - 我同意。因此,我将每个测试分解为它自己的类/主方法,并且每个测试都单独进行。结果:

1 - Performed 2500000 encodings trying to catch each in 5016ms
1 - Performed 5000000 encodings trying to catch each in 7547ms
1 - Performed 5000000 encodings trying to catch each in 7515ms
1 - Performed 5000000 encodings trying to catch each in 7531ms

2 - Performed 2500000 encodings trying to catch all in 4719ms
2 - Performed 5000000 encodings trying to catch all in 7250ms
2 - Performed 5000000 encodings trying to catch all in 7203ms
2 - Performed 5000000 encodings trying to catch all in 7250ms

3 - Performed 2500000 encodings with a deprecated method in 5297ms
3 - Performed 5000000 encodings with a deprecated method in 8015ms
3 - Performed 5000000 encodings with a deprecated method in 8063ms
3 - Performed 5000000 encodings with a deprecated method in 8219ms

有趣的观察:

  • 在它自己的 JVM 中减少了捕获每个调用与捕获循环外所有内容之间的差距(我假设由于其他迭代已经执行)
  • 我这边的 try/catch 与 URLEncoder.encode() 中的 try/catch 之间的差距现在要小得多(超过 5000000 次迭代半秒),但仍然始终如一......

【问题讨论】:

  • 以不同的顺序尝试测试:test2()、test3()、test1() 以隔离由于 JIT 编译造成的任何差异。

标签: java performance exception urlencode malformedurlexception


【解决方案1】:

按照您发布的顺序运行它:

执行了 2500000 次编码尝试 在 34208 毫秒内捕获每个
执行了 2500000 次编码,试图捕获所有 在 31708 毫秒内
执行了 2500000 次编码 在 30738 毫秒内使用已弃用的方法

颠倒顺序:

使用 a 执行了 2500000 次编码 在 32598 毫秒内弃用的方法
已执行 2500000 个编码试图捕获所有 在 31239 毫秒内
执行了 2500000 次编码 试图在 31208 毫秒内捕获每个

因此,我实际上并不认为您看到的是您所看到的(当然,test1 并不比 test3 慢 66%,这是您的基准测试所建议的)

【讨论】:

  • 嗯...我已将每个测试分解为它自己的主类,因此测试之间不能有任何优化,我看到:1 - 尝试执行 2500000 次编码在 5016 毫秒内捕获每个 1 - 执行 5000000 次编码,尝试在 7547 毫秒内捕获每个 2 - 尝试在 4719 毫秒内执行 2500000 次编码 2 - 尝试在 7250 毫秒内执行 5000000 次编码 3 - 使用不推荐使用的方法在 5297 毫秒内执行 2500000 次编码 3 -在 8015 毫秒内使用不推荐使用的方法执行了 5000000 次编码 不推荐使用的测试仍然稍慢。再一次,只有一分钟! ://
  • 废话 - 评论搞砸了格式...查看原文以获取更新
【解决方案2】:

是的,你有你的解释,我想:

由于涉及额外的方法调用,3 比 1 稍慢。

2 比任何一个都快,因为它不会在每个循环中“设置”和“拆除”与异常捕获相关的字节码。可以破解打开字节码看看与javap的区别——见http://www.theserverside.com/tt/articles/article.tss?l=GuideJavaBytecode

您使用 2 还是 1 取决于您想要哪种行为,因为它们不等价。我会选择 1 而不是 3,因为这样您就不会使用不推荐使用的方法,这比微小的速度增加更重要——但碰巧 1 无论如何都会更快。

【讨论】:

    【解决方案3】:

    请纠正我,但是test2 for循环只执行了1步,因为抛出异常并且test1在循环内捕获了异常并执行了2500000次。

    当你在循环外捕获异常时,循环不会重新开始。打印出“int i”以确定循环执行了多少步。

    第三个是最慢的,因为该方法将调用委托给已弃用的方法。

    【讨论】:

    • 实际上从未抛出异常-编码对所有异常都有效-更多的是“如果抛出异常,JVM在做什么”的问题(在每个循环上打印出一些东西来验证这一点)
    猜你喜欢
    • 2016-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-15
    • 1970-01-01
    相关资源
    最近更新 更多