Быстрый парсер Java для OffsetDateTime - PullRequest
0 голосов
/ 07 февраля 2019

Какой самый быстрый способ анализа даты / времени в OffsetDateTimes в Java?Есть ли библиотека, которая работает быстрее стандартной библиотеки?

Например,

OffsetDatetime x = Something.parse("2018-01-02T12:34:56+00:00");

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

tl; dr

При разборе менее миллисекунды вам не нужно беспокоиться об оптимизации синтаксического анализа на OffsetDateTime.Конечно, у вас должна быть более крупная рыба.

Подробности

Давайте попробуем небольшой тест.

Предупреждение: Микро-тесты общеизвестно ненадежны.Но, надеюсь, это приблизит нас к реалистическому пониманию.

Предостережение: Я срочно отправил этот код и эту публикацию.Пожалуйста, перепроверьте мою работу.

В моей слабой попытке избежать оптимизации времени выполнения JVM я использую 31 отдельное значение, по одному на каждый день января.Я повторяю это тысячу раз для списка из 31 000 человек.Затем я перетасовал список.

Тем не менее, мои результаты показывают, что во время выполнения есть большая доза оптимизации.Наносекунды за синтаксический анализ варьируются * в широких пределах по числу петель.

  • 100_000 петель = 1573 наносекунды каждый анализ (1 микросекунда)
  • 10_000 = 4243
  • 1_000 =10 177
  • 100 = 31 125
  • 1 = 693 687 нано каждый раз.(693 микросекунды, более половины миллисекунды).

Я использовал продукт Java 11 JVM Zulu от Azul Systems, реализация, основанная на OpenJDK, версия 11.0.2.Работал на MacBook Pro (Retina, 15-дюймовый, конец 2013 г.), 2,3 ГГц Intel Core i7, 16 ГБ 1600 МГц DDR3.

Сводка результатов:

Мой вывод:

Код.

System.out.println( "INFO - Starting the OffsetDateTime parsing benchmark." );

List < String > inputsShort = new ArrayList <>( 31 );
inputsShort.add( "2018-01-01T12:34:56+00:00" );
inputsShort.add( "2018-01-02T12:34:56+00:00" );
inputsShort.add( "2018-01-03T12:34:56+00:00" );
inputsShort.add( "2018-01-04T12:34:56+00:00" );
inputsShort.add( "2018-01-05T12:34:56+00:00" );
inputsShort.add( "2018-01-06T12:34:56+00:00" );
inputsShort.add( "2018-01-07T12:34:56+00:00" );
inputsShort.add( "2018-01-08T12:34:56+00:00" );
inputsShort.add( "2018-01-09T12:34:56+00:00" );
inputsShort.add( "2018-01-10T12:34:56+00:00" );
inputsShort.add( "2018-01-11T12:34:56+00:00" );
inputsShort.add( "2018-01-12T12:34:56+00:00" );
inputsShort.add( "2018-01-13T12:34:56+00:00" );
inputsShort.add( "2018-01-14T12:34:56+00:00" );
inputsShort.add( "2018-01-15T12:34:56+00:00" );
inputsShort.add( "2018-01-16T12:34:56+00:00" );
inputsShort.add( "2018-01-17T12:34:56+00:00" );
inputsShort.add( "2018-01-18T12:34:56+00:00" );
inputsShort.add( "2018-01-19T12:34:56+00:00" );
inputsShort.add( "2018-01-20T12:34:56+00:00" );
inputsShort.add( "2018-01-21T12:34:56+00:00" );
inputsShort.add( "2018-01-22T12:34:56+00:00" );
inputsShort.add( "2018-01-23T12:34:56+00:00" );
inputsShort.add( "2018-01-24T12:34:56+00:00" );
inputsShort.add( "2018-01-25T12:34:56+00:00" );
inputsShort.add( "2018-01-26T12:34:56+00:00" );
inputsShort.add( "2018-01-27T12:34:56+00:00" );
inputsShort.add( "2018-01-28T12:34:56+00:00" );
inputsShort.add( "2018-01-29T12:34:56+00:00" );
inputsShort.add( "2018-01-30T12:34:56+00:00" );
inputsShort.add( "2018-01-31T12:34:56+00:00" );

int loops = 100; // 100_000=1,573 nanos each parse. 10_000=4,243. 1_000=10,177. 100=31,125. 1=693,687 nanos each parse.
List < String > inputs = new ArrayList <>( inputsShort.size() * loops );
for ( int i = 1 ; i <= loops ; i++ ) {
    inputs.addAll( inputsShort );
}
Collections.shuffle( inputs );
//System.out.println( inputs );

long start = System.nanoTime();
for ( String input : inputs ) {
    OffsetDateTime odt = OffsetDateTime.parse( input );
}
long stop = System.nanoTime();
long nanosPerParse = ( ( stop - start ) / inputs.size() );
System.out.println( "INFO: nanosPerParse: " + nanosPerParse + " for a count of: " + inputs.size() + "." );
0 голосов
/ 07 февраля 2019

Насколько мне известно, ответ - нет, другой библиотеки для разбора строк, таких как 2018-01-02T12:34:56+00:00" (формат ISO 8601), в OffsetDateTime нет.Я бы ожидал услышать или прочитать об этом, если бы он существовал.

Я нахожусь на тонком льду со следующим пунктом, но у меня также сложилось впечатление, что стандартная библиотека (AKA java.time)достаточно эффективен и, вероятно, примерно так же быстро, как вы можете ожидать.

Редактировать: Мне стало любопытно, и я написал свой собственный метод разбора, чтобы посмотреть, смогу ли я превзойти одно-argOffsetDateTime.parse.Я был.Мой собственный метод (источник ниже) не обладает гибкостью встроенного метода, он принимает только один из огромного числа вариантов стандартного формата, что может быть его сильной стороной с точки зрения производительности.Разбор вашей строки миллион раз занял:

  • 1,034 секунды, используя OffsetDateTime.parse
  • 0,117 секунды, используя мой собственный метод

Это не рекомендация!Я, вероятно, никогда не использовал бы свой собственный метод.Для подавляющего большинства целей затраты на обслуживание не будут стоить этого.Если однажды появится другой вариант ISO 8601, у вас возникнет дорогостоящая проблема поддержки и исправления ошибки.

Мой метод довольно прост:

private static final OffsetDateTime parse(String s) {
    char offsetSign;
    if (s.length() != 25
            || s.charAt(4) != '-'
            || s.charAt(7) != '-'
            || s.charAt(10) != 'T'
            || s.charAt(13) != ':'
            || s.charAt(16) != ':'
            || ((offsetSign = s.charAt(19)) != '+' && offsetSign != '-')
            || s.charAt(22) != ':') {
        throw new IllegalArgumentException();
    }
    int offsetHours = Integer.parseInt(s.substring(20, 22));
    int offsetMinutes = Integer.parseInt(s.substring(23, 25));
    if (offsetSign == '-') {
        offsetHours = -offsetHours;
        offsetMinutes = -offsetMinutes;
    }
    return OffsetDateTime.of(Integer.parseInt(s.substring(0, 4)),
            Integer.parseInt(s.substring(5, 7)),
            Integer.parseInt(s.substring(8, 10)), 
            Integer.parseInt(s.substring(11, 13)), 
            Integer.parseInt(s.substring(14, 16)), 
            Integer.parseInt(s.substring(17, 19)), 
            0,
            ZoneOffset.ofHoursMinutes(offsetHours, offsetMinutes));
}

Я знаю об ошибках вкод.Я не думаю, что стоит тщательно проверять и исправлять ошибки в этом ответе, поскольку он вряд ли сильно повлияет на производительность.

...