Java的最快的解析器OffsetDateTime

问题描述 投票:1回答:2

什么是解析日期/时间到OffsetDateTime Java中的最快方法是什么?是否有比标准库快库?

EG

OffsetDatetime x = Something.parse("2018-01-02T12:34:56+00:00");
java datetime java-time datetime-parsing
2个回答
2
投票

据我所知的答案是否定的,有对于解析字符串像2018-01-02T12:34:56+00:00"(ISO 8601格式)转换成OffsetDateTime对象没有其他库。我没有料想到会听到或读到它,已经存在一个。

我如履薄冰下一个点,但我也印象中的标准库(AKA java.time)是足够的效率,并可能一样快,你可以期望得到之下。

编辑:我得到了好奇,写我自己的解析方法,看看我是否能够跑赢单ARG OffsetDateTime.parse。我曾是。我自己的方法(来源以下)还没有得到内置方法的灵活性,它接受只有一个出大量的标准格式的变体,这可能是其强大的运算性能,明智的。解析你的字符串一百万次了:

  • 1.034秒使用OffsetDateTime.parse
  • 用我自己的方法0.117秒

这不是一个推荐!我可能永远不会用我自己的方法。对于绝大多数目的的维护负担不会是值得的。如果有一天,ISO 8601的不同变种轮番上涨,你将有一个昂贵的支持问题和bug修复。

我的方法很简单:

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));
}

我知道在代码中的bug。我不认为这是值得进行彻底的测试和修复bug的这个答案,因为它不可能太大影响性能。


1
投票

tl;dr

在每解析不到一毫秒,你不必担心被OffsetDateTime优化分析。当然,你必须有更大的鱼鱼苗。

Details

让我们尝试一个小的基准测试。

警告:微基准测试是非常不可靠。但希望这会让我们接近真实的认识。

警告:我冲到此代码,这个帖子。请仔细检查我的工作。

在我无力的尝试由JVM避免运行时优化,我用31倍不同的值,一个用于月份的每一天。我重复这些一千倍的31,000名单。然后,我拖着列表。

然而我的研究结果表明有在运行时优化大剂量的。每解析纳秒内循环的数量而变化*很大。

  • 100_000循环= 1573纳秒每个解析(1微秒)
  • 10_000 = 4,243
  • 1_000 = 10,177
  • 100 = 31,125
  • 1 = 693687 NANOS每个解析。 (693微秒,超过半毫秒)。

我用Java的JVM 11祖鲁产品由Azul系统,基于OpenJDK的实现,11.0.2版。然在MacBook Pro上(视网膜,15英寸,2013晚期),2.3 GHz的英特尔酷睿i7,16 GB 1600 MHz的DDR3。

结果总结:

我的结论:

  • 不要担心你的解析输入OffsetDateTime字符串。
  • 你可能会落入premature optimization的陷阱。

码。

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() + "." );
© www.soinside.com 2019 - 2024. All rights reserved.