Циклы исключений Java и устаревание (или это проблема URLEncoding?)

StackOverflow https://stackoverflow.com/questions/905126

Вопрос

Я только что написал целое аннотацию о том, как я достиг этой точки, но решил, что проще опубликовать код и оставить все как есть :)

Насколько я могу судить, производительность 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");
    }

}

Запуск дает мне (JDK 1.6.0_13 в Windows XP) результат:

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 на моей стороне и try/catch внутри URLEncoder.encode() теперь намного меньше (полсекунды за 5000000 итераций), но все равно сохраняется...
Это было полезно?

Решение

Запускаем в том порядке, в котором вы разместили:

Выполнено 2500000 кодировок, пытающихся поймать каждый в 34208ms
Выполнено 2500000 кодировок, пытаясь поймать все в 31708ms
Выполнено 2500000 кодировок с устаревшим методом в 30738ms

Обратный порядок:

Выполнено 2500000 кодировок с устаревший метод в 32598ms
Выполнено 2500000 кодировок пытаются поймать все в 31239ms
Выполнено 2500000 кодировок пытаясь поймать каждого в 31208ms

Поэтому я на самом деле не думаю, что вы видите то, что, по вашему мнению, вы видите (конечно, test1 не на 66% медленнее, чем test3, как показывают ваши тесты)

Другие советы

Да, у вас есть объяснение, я думаю:

3 немного медленнее, чем 1, из-за дополнительного вызова метода.

2 быстрее, чем любой из них, поскольку он не «настраивает» и не «уничтожает» байт-код, связанный с перехватом исключений, в каждом цикле.Вы можете взломать байт-код, чтобы увидеть разницу с javap — см. http://www.theserverside.com/tt/articles/article.tss?l=GuideJavaBytecode

Используете ли вы 2 или 1, зависит от того, какое поведение вы хотите, поскольку они не эквивалентны.Я бы выбрал 1 вместо 3, поскольку в этом случае вы не используете устаревший метод, который более важен, чем небольшое увеличение скорости, но, как оказалось, 1 в любом случае быстрее.

Пожалуйста, поправьте меня, но цикл for test2 выполняет только 1 шаг из-за выбрасываемого исключения, а test1 перехватывает исключение внутри цикла и выполняется 2500000 раз.

Если вы поймаете исключение вне цикла, цикл не запустится снова.Распечатайте «int i», чтобы узнать, сколько шагов сделал цикл.

Третий — самый медленный, поскольку метод делегирует вызов устаревшему методу.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top