作者:温绍锦(高铁) 阿里云计算平台团队
在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
JDK的Character提供了isWhiteSpace方法,逻辑不能定制化,不支持上面的'\b'字符判空,但为了性能比较,也加入进来。
boolean space = Character.isWhitespace(ch);
这个常规办法,用6个并列的or判断。所有的字符检测都需要做6次判断,性能较差。
- boolean space = ch == ' '
- || ch == '\n'
- || ch == '\r'
- || ch == '\f'
- || ch == '\t'
- || ch == '\b';
由于空白字符最大的是空格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');
这种算法,在JDK 17下性能有较大提升。在大量输入是非空字符时,性能并不出色。
- boolean space;
- switch (ch) {
- case ' ':
- case '\n':
- case '\r':
- case '\t':
- case '\b':
- case '\f':
- space = true;
- break;
- default:
- space = false;
- break;
- }
通过预计算一个常量的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;
使用阿里云x64当前代计算型4核8G服务器,CPU型号 Intel Xeon(Ice Lake) Platinum 8369B

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

下载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
- {"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
- }
- }
执行测试代码
- 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
| 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
| 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性能最理想。