代码之家  ›  专栏  ›  技术社区  ›  Martin

Java异常循环和弃用(或者它是URLCOND编码的东西)?

  •  0
  • Martin  · 技术社区  · 15 年前

    我刚刚写了一个关于我是如何达到这一点的完整的宣传,但是我认为发布代码并将其留在那里更容易:)

    据我所知,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_)输出:

    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
    

    所以,反应非常接近(我们说的是一些无关紧要的事情,这是不相关的),btu我很好奇!

    后来…

    有人建议说有一些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次迭代的半秒),但仍然一致存在…
    3 回复  |  直到 15 年前
        1
  •  1
  •   Catchwa    15 年前

    按您发布的顺序运行:

    进行了2500000次编码尝试 34208ms内捕捉每一个
    进行了2500000次编码,试图捕捉所有 在31708MS
    执行了2500000次编码 在30738ms中使用了已弃用的方法

    颠倒顺序:

    进行了2500000次编码 32598ms中已弃用的方法
    表演 2500000个编码试图捕捉所有 31239毫秒
    执行了2500000次编码 试图在31208ms内抓住每一个

    因此,我并不认为你看到了你认为你看到的(当然,test1比test3慢66%,这正是你的基准建议的)。

        2
  •  0
  •   Sean Owen    15 年前

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

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

    2比两者都快,因为它不“设置”和“关闭”异常,在每个循环中捕获相关的字节码。您可以打开字节代码来查看javap的区别——请参见 http://www.theserverside.com/tt/articles/article.tss?l=GuideJavaBytecode

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

        3
  •  0
  •   Markus Lausberg    15 年前

    请更正我的错误,但是test2 for循环只执行1步,因为引发了异常,test1在循环中捕获了异常,并执行了2500000次。

    当捕获循环外的异常时,循环将不再启动。打印“int i”以确定循环执行了多少步。

    第三个是最慢的,因为方法将调用委托给不推荐使用的方法。