如何快速检测是否为空白字符

发布于:2023-01-20 ⋅ 阅读:(500) ⋅ 点赞:(0)

作者:温绍锦(高铁)   阿里云计算平台团队

在Parser场景,包括SQL Parser和JSON Parser,如何更快检测空白字符是一个提升性能的关键点。笔者有多年SQL Parser和JSON Parser的经验,把我所知道的一些检测空白的方法分享给大家。

一、什么是空白字符

如果采用json.org的标准,空白字符包括:

'\b' -- ASCII 8
'\t' -- ASCII 9
'\n' -- ASCII 10
'\f' -- ASCII 12
'\r' -- ASCII 13
' '  -- ASCII 32

二、检测空白字符的5种方法

2.1 方法1

JDK的Character提供了isWhiteSpace方法,逻辑不能定制化,不支持上面的'\b'字符判空,但为了性能比较,也加入进来。

boolean space = Character.isWhitespace(ch);

2.1 方法2

这个常规办法,用6个并列的or判断。所有的字符检测都需要做6次判断,性能较差。

boolean space = ch == ' '
    || ch == '\n'
    || ch == '\r'
    || ch == '\f'
    || ch == '\t'
    || ch == '\b';

2.2 方法3

由于空白字符最大的是空格ASCII 32,在方法2的基础上先做一个预先检测,这样就能获得非常好的性能,但当输入的有大量空白字符\b时,就就会面临方法2的问题。fastjson 1.x ( GitHub - alibaba/fastjson: A fast JSON parser/generator for Java. )判空用的是这个方法。

boolean space = ch <= ' '
    && (ch == ' '
        || ch == '\n'
        || ch == '\r'
        || ch == '\f'
        || ch == '\t'
        || ch == '\b');

2.3 方法4

这种算法,在JDK 17下性能有较大提升。在大量输入是非空字符时,性能并不出色。

boolean space;
switch (ch) {
    case ' ':
    case '\n':
    case '\r':
    case '\t':
    case '\b':
    case '\f':
        space = true;
        break;
    default:
        space = false;
        break;
}

2.4 方法5

通过预计算一个常量的long,然后做bitAnd判断。
fastjson2 ( GitHub - alibaba/fastjson2: 🚄 FASTJSON2是FASTJSON项目的重要升级,目标是为下一个十年提供一个高性能的JSON库 )判空用的是这个方法。

static final long SPACE = (1L << ' ') 
    | (1L << '\n') 
    | (1L << '\r') 
    | (1L << '\f') 
    | (1L << '\t') 
    | (1L << '\b');


boolean space = ch <= ' ' && ((1L << ch) & SPACE) != 0;

三、测试环境

3.1 x86服务器

使用阿里云x64当前代计算型4核8G服务器,CPU型号 Intel Xeon(Ice Lake) Platinum 8369B

3.2 ARM服务器

使用阿里云ARM当前代计算型4核8G服务器,CPU型号 Ampere Altra / AltraMax

3.3 JDK

下载Oracle最新的LTS版本Linux JDK

jdk1.8.0_333_x64
jdk-11.0.15.1_x64
jdk-17.0.3.1_x64
jdk1.8.0_333_aarch64
jdk-11.0.15.1_aarch64
jdk-17.0.3.1_aarch64

3.4 测试数据

{"images": [{
      "height":768,
      "size":"LARGE",
      "title":"Javaone Keynote",
      "uri":"http://javaone.com/keynote_large.jpg",
      "width":1024
    }, {
      "height":240,
      "size":"SMALL",
      "title":"Javaone Keynote",
      "uri":"http://javaone.com/keynote_small.jpg",
      "width":320
    }
  ],
  "media": {
    "bitrate":262144,
    "duration":18000000,
    "format":"video/mpg4",
    "height":480,
    "persons": [
      "Bill Gates",
      "Steve Jobs"
    ],
    "player":"JAVA",
    "size":58982400,
    "title":"Javaone Keynote",
    "uri":"http://javaone.com/keynote.mpg",
    "width":640
  }
}

3.5 测试代码及运行方法

测试代码:
fastjson2/benchmark/src/main/java/com/alibaba/fastjson2/benchmark at main · alibaba/fastjson2 · GitHub

执行测试代码

git clone https://github.com/alibaba/fastjson2
cd fastjson2
mvn clean install -Dmaven.test.skip
java -cp benchmark/target/fastjson2-benchmarks.jar com.alibaba.fastjson2.benchmark.SpaceCheckBenchmark

四、JMH测试结果

4.1 x64测试结果

JDK8 JDK11 JDK17
方法1 1756.884 1692.215 1770.658
方法2 1911.820 1866.888 1903.105
方法3 3496.629 4228.972 3956.434
方法4 2798.679 2910.525 2876.148
方法5 3522.462 3694.007 4474.286
  • 原始数据
### jdk1.8.0_333_x64
Benchmark                                   Mode  Cnt     Score      Error   Units
SpaceCheckBenchmark.CharacterIsWhitespace  thrpt    5  1756.884 ?    2.202  ops/ms
SpaceCheckBenchmark.spaceOr                thrpt    5  1911.820 ?    5.965  ops/ms
SpaceCheckBenchmark.spaceOrPreCheck        thrpt    5  3496.629 ?  739.373  ops/ms
SpaceCheckBenchmark.spaceSwitch            thrpt    5  2798.679 ? 1024.227  ops/ms
SpaceCheckBenchmark.spaceBitAnd            thrpt    5  3522.462 ?  859.084  ops/ms

### jdk-11.0.15.1_x64
Benchmark                                   Mode  Cnt     Score     Error   Units
SpaceCheckBenchmark.CharacterIsWhitespace  thrpt    5  1692.215 ? 363.925  ops/ms
SpaceCheckBenchmark.spaceOr                thrpt    5  1866.888 ?  33.836  ops/ms
SpaceCheckBenchmark.spaceOrPreCheck        thrpt    5  4228.972 ? 212.870  ops/ms
SpaceCheckBenchmark.spaceSwitch            thrpt    5  2910.525 ? 584.406  ops/ms
SpaceCheckBenchmark.spaceBitAnd            thrpt    5  3694.007 ? 158.193  ops/ms


### jdk-17.0.3.1_x64
Benchmark                                   Mode  Cnt     Score     Error   Units
SpaceCheckBenchmark.CharacterIsWhitespace  thrpt    5  1770.658 ? 651.168  ops/ms
SpaceCheckBenchmark.spaceOr                thrpt    5  1903.105 ?  40.520  ops/ms
SpaceCheckBenchmark.spaceOrPreCheck        thrpt    5  3956.434 ? 628.745  ops/ms
SpaceCheckBenchmark.spaceSwitch            thrpt    5  2876.148 ? 127.401  ops/ms
SpaceCheckBenchmark.spaceBitAnd            thrpt    5  4474.286 ? 539.261  ops/ms

4.1 ARM测试结果

JDK8 JDK11 JDK17
方法1 911.795 785.339 1269.834
方法2 789.439 833.830 842.177
方法3 2304.419 2429.907 2146.953
方法4 880.387 1124.967 1540.419
方法5 2363.957 2392.123 2570.536
  • 原始数据
### jdk1.8.0_333_aarch64
Benchmark                                   Mode  Cnt     Score     Error   Units
SpaceCheckBenchmark.CharacterIsWhitespace  thrpt    5   911.795 ?   5.171  ops/ms
SpaceCheckBenchmark.spaceOr                thrpt    5   789.439 ? 163.867  ops/ms
SpaceCheckBenchmark.spaceOrPreCheck        thrpt    5  2304.419 ?  29.643  ops/ms
SpaceCheckBenchmark.spaceSwitch            thrpt    5   880.387 ?  63.411  ops/ms
SpaceCheckBenchmark.spaceBitAnd            thrpt    5  2363.957 ? 759.335  ops/ms

### jdk-11.0.15.1_aarch64
Benchmark                                   Mode  Cnt     Score     Error   Units
SpaceCheckBenchmark.CharacterIsWhitespace  thrpt    5   785.339 ?   5.361  ops/ms
SpaceCheckBenchmark.spaceOr                thrpt    5   833.830 ?  14.402  ops/ms
SpaceCheckBenchmark.spaceOrPreCheck        thrpt    5  2429.907 ?   9.120  ops/ms
SpaceCheckBenchmark.spaceSwitch            thrpt    5  1124.967 ? 811.435  ops/ms
SpaceCheckBenchmark.spaceBitAnd            thrpt    5  2392.123 ? 381.551  ops/ms

### jdk-17.0.3.1_aarch64
Benchmark                                   Mode  Cnt     Score     Error   Units
SpaceCheckBenchmark.CharacterIsWhitespace  thrpt    5  1269.834 ?   5.587  ops/ms
SpaceCheckBenchmark.spaceOr                thrpt    5   842.177 ?   7.969  ops/ms
SpaceCheckBenchmark.spaceOrPreCheck        thrpt    5  2146.953 ? 518.320  ops/ms
SpaceCheckBenchmark.spaceSwitch            thrpt    5  1540.419 ?  32.401  ops/ms
SpaceCheckBenchmark.spaceBitAnd            thrpt    5  2570.536 ?   2.284  ops/ms

五、结论

综合来看,无论是x64还是aarch64,方法5性能最理想。

本文含有隐藏内容,请 开通VIP 后查看