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


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

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

    一、什么是空白字符

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

    1. '\b' -- ASCII 8
    2. '\t' -- ASCII 9
    3. '\n' -- ASCII 10
    4. '\f' -- ASCII 12
    5. '\r' -- ASCII 13
    6. ' ' -- ASCII 32

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

    2.1 方法1

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

    boolean space = Character.isWhitespace(ch);

    2.1 方法2

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

    1. boolean space = ch == ' '
    2. || ch == '\n'
    3. || ch == '\r'
    4. || ch == '\f'
    5. || ch == '\t'
    6. || ch == '\b';

    2.2 方法3

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

    1. boolean space = ch <= ' '
    2. && (ch == ' '
    3. || ch == '\n'
    4. || ch == '\r'
    5. || ch == '\f'
    6. || ch == '\t'
    7. || ch == '\b');

    2.3 方法4

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

    1. boolean space;
    2. switch (ch) {
    3. case ' ':
    4. case '\n':
    5. case '\r':
    6. case '\t':
    7. case '\b':
    8. case '\f':
    9. space = true;
    10. break;
    11. default:
    12. space = false;
    13. break;
    14. }

    2.4 方法5

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

    1. static final long SPACE = (1L << ' ')
    2. | (1L << '\n')
    3. | (1L << '\r')
    4. | (1L << '\f')
    5. | (1L << '\t')
    6. | (1L << '\b');
    7. 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

    1. jdk1.8.0_333_x64
    2. jdk-11.0.15.1_x64
    3. jdk-17.0.3.1_x64
    4. jdk1.8.0_333_aarch64
    5. jdk-11.0.15.1_aarch64
    6. jdk-17.0.3.1_aarch64

    3.4 测试数据

    1. {"images": [{
    2. "height":768,
    3. "size":"LARGE",
    4. "title":"Javaone Keynote",
    5. "uri":"http://javaone.com/keynote_large.jpg",
    6. "width":1024
    7. }, {
    8. "height":240,
    9. "size":"SMALL",
    10. "title":"Javaone Keynote",
    11. "uri":"http://javaone.com/keynote_small.jpg",
    12. "width":320
    13. }
    14. ],
    15. "media": {
    16. "bitrate":262144,
    17. "duration":18000000,
    18. "format":"video/mpg4",
    19. "height":480,
    20. "persons": [
    21. "Bill Gates",
    22. "Steve Jobs"
    23. ],
    24. "player":"JAVA",
    25. "size":58982400,
    26. "title":"Javaone Keynote",
    27. "uri":"http://javaone.com/keynote.mpg",
    28. "width":640
    29. }
    30. }

    3.5 测试代码及运行方法

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

    执行测试代码

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

    四、JMH测试结果

    4.1 x64测试结果

    JDK8JDK11JDK17
    方法11756.8841692.2151770.658
    方法21911.8201866.8881903.105
    方法33496.6294228.9723956.434
    方法42798.6792910.5252876.148
    方法53522.4623694.0074474.286
    • 原始数据
    1. ### jdk1.8.0_333_x64
    2. Benchmark Mode Cnt Score Error Units
    3. SpaceCheckBenchmark.CharacterIsWhitespace thrpt 5 1756.884 ? 2.202 ops/ms
    4. SpaceCheckBenchmark.spaceOr thrpt 5 1911.820 ? 5.965 ops/ms
    5. SpaceCheckBenchmark.spaceOrPreCheck thrpt 5 3496.629 ? 739.373 ops/ms
    6. SpaceCheckBenchmark.spaceSwitch thrpt 5 2798.679 ? 1024.227 ops/ms
    7. SpaceCheckBenchmark.spaceBitAnd thrpt 5 3522.462 ? 859.084 ops/ms
    8. ### jdk-11.0.15.1_x64
    9. Benchmark Mode Cnt Score Error Units
    10. SpaceCheckBenchmark.CharacterIsWhitespace thrpt 5 1692.215 ? 363.925 ops/ms
    11. SpaceCheckBenchmark.spaceOr thrpt 5 1866.888 ? 33.836 ops/ms
    12. SpaceCheckBenchmark.spaceOrPreCheck thrpt 5 4228.972 ? 212.870 ops/ms
    13. SpaceCheckBenchmark.spaceSwitch thrpt 5 2910.525 ? 584.406 ops/ms
    14. SpaceCheckBenchmark.spaceBitAnd thrpt 5 3694.007 ? 158.193 ops/ms
    15. ### jdk-17.0.3.1_x64
    16. Benchmark Mode Cnt Score Error Units
    17. SpaceCheckBenchmark.CharacterIsWhitespace thrpt 5 1770.658 ? 651.168 ops/ms
    18. SpaceCheckBenchmark.spaceOr thrpt 5 1903.105 ? 40.520 ops/ms
    19. SpaceCheckBenchmark.spaceOrPreCheck thrpt 5 3956.434 ? 628.745 ops/ms
    20. SpaceCheckBenchmark.spaceSwitch thrpt 5 2876.148 ? 127.401 ops/ms
    21. SpaceCheckBenchmark.spaceBitAnd thrpt 5 4474.286 ? 539.261 ops/ms

    4.1 ARM测试结果

    JDK8JDK11JDK17
    方法1911.795785.3391269.834
    方法2789.439833.830842.177
    方法32304.4192429.9072146.953
    方法4880.3871124.9671540.419
    方法52363.9572392.1232570.536
    • 原始数据
    1. ### jdk1.8.0_333_aarch64
    2. Benchmark Mode Cnt Score Error Units
    3. SpaceCheckBenchmark.CharacterIsWhitespace thrpt 5 911.795 ? 5.171 ops/ms
    4. SpaceCheckBenchmark.spaceOr thrpt 5 789.439 ? 163.867 ops/ms
    5. SpaceCheckBenchmark.spaceOrPreCheck thrpt 5 2304.419 ? 29.643 ops/ms
    6. SpaceCheckBenchmark.spaceSwitch thrpt 5 880.387 ? 63.411 ops/ms
    7. SpaceCheckBenchmark.spaceBitAnd thrpt 5 2363.957 ? 759.335 ops/ms
    8. ### jdk-11.0.15.1_aarch64
    9. Benchmark Mode Cnt Score Error Units
    10. SpaceCheckBenchmark.CharacterIsWhitespace thrpt 5 785.339 ? 5.361 ops/ms
    11. SpaceCheckBenchmark.spaceOr thrpt 5 833.830 ? 14.402 ops/ms
    12. SpaceCheckBenchmark.spaceOrPreCheck thrpt 5 2429.907 ? 9.120 ops/ms
    13. SpaceCheckBenchmark.spaceSwitch thrpt 5 1124.967 ? 811.435 ops/ms
    14. SpaceCheckBenchmark.spaceBitAnd thrpt 5 2392.123 ? 381.551 ops/ms
    15. ### jdk-17.0.3.1_aarch64
    16. Benchmark Mode Cnt Score Error Units
    17. SpaceCheckBenchmark.CharacterIsWhitespace thrpt 5 1269.834 ? 5.587 ops/ms
    18. SpaceCheckBenchmark.spaceOr thrpt 5 842.177 ? 7.969 ops/ms
    19. SpaceCheckBenchmark.spaceOrPreCheck thrpt 5 2146.953 ? 518.320 ops/ms
    20. SpaceCheckBenchmark.spaceSwitch thrpt 5 1540.419 ? 32.401 ops/ms
    21. SpaceCheckBenchmark.spaceBitAnd thrpt 5 2570.536 ? 2.284 ops/ms

    五、结论

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

  • 相关阅读:
    Redis 内存满了怎么办?这样置才正确!
    SpringBoot 使用EasyExcel 导出Excel报表(单元格合并)
    C++之容器类有趣的实验(二百四十一)
    修改Jenkins主目录
    iapp卸载指定软件代码,iapp删除文件夹代码
    MASA Framework -- EventBus入门与设计
    Golang 字符串
    Hexo博客使用aplayer音乐播放插件
    make 和 makefile 的使用 ###通俗易懂
    HTML - 请你谈一谈img标签图片和background背景图片的区别
  • 原文地址:https://blog.csdn.net/AlibabaTech1024/article/details/126307501