近日,GitHub开源了一JSON解析器simdjson,通过与其他常用解析器的对比实验,结果显示,simdjson的解析速度达到2.2GB/s,远远秒杀其他解析器,在下文中,我们将为大家详细介绍simdjson。以下全文为simdjson在GitHub上的文档。

JSON文档在互联网上无处不在,服务器花费大量时间来解析这些文档。我们希望在进行完全验证(包括字符编码)的同时尽可能使用常用的SIMD指令来加速JSON的解析。

一些性能结果

相比最先进的解析器(如RapidJSON),我们可能使用四分之一或更少的指令,也只有sajson的一半。据我们所知,simdjson是第一个在商用处理器上以每秒千兆字节速度运行的完全验证JSON解析器。

在Skylake处理器上,各种解析器解析twitter.json文件的速度(以GB/s为单位)如下所示。

基本要求

  • 通过Visual Studio 2017或更高版本支持Linux、macOS以及Windows等平台;

  • 带有AVX2的处理器;

  • 支持最近的C++编译器(例如,GNU GCC或LLVM CLANG或Visual Studio 2017),我们假设是C++ 17,GNU GCC 7或更高版本,或者LLVM的clang 6或更高版本;

  • 提供一些基准测试脚本,可以是bash和其他常用的实用命令程序,但是是可选的。

许可

代码采用Apache License 2.0许可。

在Windows下,我们使用windows/dirent_portable.h文件(在我们的库代码之外)构建了一些工具:基于自由的MIT许可。

代码示例

#include \u0026quot;simdjson/jsonparser.h\u0026quot;/...const char * filename = ...  use whatever means you want to get a string of your JSON documentstd::string_view p = get_corpus(filename);ParsedJson pj;pj.allocateCapacity(p.size()); // allocate memory for parsing up to p.size() bytesbool is_ok = json_parse(p, pj); // do the parsing, return false on error// parsing is done!// You can safely delete the string contentfree((void*)p.data());// the ParsedJson document can be used here// js can be reused with other json_parse calls.

如果你不介意为每个新的JSON文档分配内存,也可以使用更简单的API:

#include \u0026quot;simdjson/jsonparser.h\u0026quot;/...const char * filename = ... //std::string_view p = get_corpus(filename);ParsedJson pj = build_parsed_json(p); // do the parsing// you no longer need p at this point, can do aligned_free((void*)p.data())if( ! pj.isValid() ) {    // something went wrong}

用法

简单的头文件

头文件可以看一下代码库的“singleheader”,用法可以看一下“amalgamation_demo.cpp”文件。这里不要求使用特定的构建系统:只需要将文件复制到项目中的路径中即可。然后,你就可以包含它们:

#include \u0026lt;iostream\u0026gt;#include \u0026quot;simdjson.h\u0026quot;#include \u0026quot;simdjson.cpp\u0026quot;int main(int argc, char *argv[]) {  const char * filename = argv[1];   std::string_view p = get_corpus(filename);  ParsedJson pj = build_parsed_json(p); // do the parsing  if( ! pj.isValid() ) {    std::cout \u0026lt;\u0026lt; \u0026quot;not valid\u0026quot; \u0026lt;\u0026lt; std::endl;  } else {    std::cout \u0026lt;\u0026lt; \u0026quot;valid\u0026quot; \u0026lt;\u0026lt; std::endl;  }  return EXIT_SUCCESS;}

注意:在某些环境中,可能需要预编译simdjson.cpp,而不是包含它。

在Linux或macOS等平台上使用旧版Makefile

要求:最近的clang(或gcc)和make。我们建议至少使用GNU GCC/G ++ 7或LLVM clang 6,Linux或macOS系统。

测试:

makemake test

运行基准测试:

make parse./parse jsonexamples/twitter.json

在Linux上,parse命令提供了性能计数器的详细分析。

运行其他作为比较的基准测试(使用其他解析器):

make benchmark

使用Linux或macOS等平台上的CMake

要求:需要最新版本的cmake,在macOS上,安装cmake的最简单方法可能是使用brew。

brew install cmake

你需要一个像clang或gcc这样的新版编译器。我们建议至少使用GNU GCC/G ++ 7或LLVM clang 6。例如,你可以使用brew安装最新的编译器:

brew install gcc@8

可选:你需要通过设置CC和CXX变量告诉cmake你希望使用哪个编译器。在bash中,你可以使用export CC = gcc-7和export CXX = g+±7等命令。

构建:在项目代码库中执行以下命令:

mkdir buildcd buildcmake ..makemake test

CMake将会构建出一个库。默认情况下,它构建的是一个共享库(例如,Linux上的libsimdjson.so)。

你可以构建一个静态库:

mkdir buildstaticcd buildstaticcmake -DSIMDJSON_BUILD_STATIC=ON ..make make test

在某些情况下,你可能希望指定编译器,尤其是当系统默认编译器太旧的情况下。你可以按以下步骤操作:

brew install gcc@8mkdir buildcd buildexport CXX=g++-8 CC=gcc-8cmake ..makemake test

通过Visual Studio在Windows上使用CMake

我们假设你拥有一台至少装有Visual Studio 2017的普通Windows PC,并支持AVX2的x64处理器(2013 Haswell或更高版本)。

  • 从GitHub获取simdjson代码,例如,使用GitHub Desktop克隆它。

  • 安装CMake。在安装时,请确保可以从命令行使用cmake。请选择最新版本的cmake。

  • 在simdjson中创建一个子目录,例如VisualStudio。

  • 在shell中转到这个新创建的目录。

  • 在shell中键入cmake -DCMAKE_GENERATOR_PLATFORM=x64 …(或者,如果要构建DLL,可以使用命令行cmake -DCMAKE_GENERATOR_PLATFORM=x64 -DSIMDJSON_BUILD_STATIC=OFF …)。

  • 最后一个命令在新创建的目录(例如simdjson.sln)中创建了一个Visual Studio解决方案文件。在Visual Studio中打开这个文件。你现在应该能够构建项目并运行测试。例如,在“Solution Explorer”窗口中,右键单击“ALL_BUILD”,并选择“Build”。要测试代码,仍然在Solution Explorer窗口中,选择RUN_TESTS,再选择Build。

工具

  • json2json mydoc.json解析文档,构造模型,然后将结果输出到标准输出。

  • json2json -d mydoc.json解析文档,构造模型,然后将模型输出到标准输出。格式在随附的文件tape.md中有描述。

  • minify mydoc.json缩小JSON文档,将结果输出到标准输出。缩小意味着删除不必要的空格。

范围

我们提供了一个非常快的解析器。它根据各种规格对输入进行完全的验证。解析器会构建一个不可变(只读)的DOM(文档对象模型),供后续访问。

为了简化工程,我们做了一些假设。

  • 支持UTF-8(以及ASCII),没有别的(没有Latin,没有UTF-16)。我们不认为这是一个真正的限制,因为我们不认为会有哪个严肃的应用程序需要在没有ASCII或UTF-8编码的情况下处理JSON数据。

  • 我们将字符串存储为以NULL作为终止符的C字符串。因此,我们假设字符串中不包含NULL字符。

  • 我们假设支持AVX2,这在AMD和英特尔生产的所有最新主流x86处理器中都可用。不支持非x86处理器,尽管我们可以支持。我们计划支持ARM处理器。

  • 如果发生故障,我们只会报告故障,而不会指出问题的性质。

  • 在规范允许的情况下,我们允许对象内存在重复的key。

  • 性能针对跨越几千字节到几兆字节的JSON文档进行了优化:解析很多小型JSON文档和一个大JSON文档的性能问题是不一样的。

我们的目标不是要提供通用的JSON库。像RapidJSON这样的库不仅提供了解析功能,它还可以用来生成JSON,并提供了各种其他方便的功能。我们只解析文档。

特性

  • 不需改输入的字符串。(像sajson和RapidJSON这样的解析器使用输入字符串作为缓冲区。)

  • 将整数和浮点数解析为单独的类型,这样可以支持[-9223372036854775808,9223372036854775808]区间的64位整数,就像Java的long或C/C++的long long。在区分整数和浮点数的解析器中,并非所有解析器都支持64位整数。(例如,sajson不支持包含大于或等于2147483648整数的JSON文件。FreeJSON将长整数解析为浮点数。)当我们无法将整数表示为带符号的64位值时,我们就拒绝解析JSON文档。

  • 在解析过程中进行完整的UTF-8验证。(像fastjson、gason和dropbox json11这样的解析器不会进行UTF-8验证。)

  • 完全验证数字。(像gason和ultranjson这样的解析器会接受[0e+]这样的数字。)

  • 验证字符串内容中的未转义字符。(像fastjson和ultrajson这样的解析器接受字符串中未转义的换行符和制表符。)

架构

解析器分三个阶段:

  • 阶段1,(查找标记)快速标识结构元素、字符串等。我们在这个阶段验证UTF-8编码。

  • 阶段2,(结构构建)构建排序的“树”(物化为磁带),以方便访问数据。我们在这个阶段解析字符串和数字。

访问已解析的文档

以下是将解析后的JSON转储回字符串的代码示例:

ParsedJson::iterator pjh(pj);    if (!pjh.isOk()) {      std::cerr \u0026lt;\u0026lt; \u0026quot; Could not iterate parsed result. \u0026quot; \u0026lt;\u0026lt; std::endl;      return EXIT_FAILURE;    }    compute_dump(pj);    //    // where compute_dump is :void compute_dump(ParsedJson::iterator \u0026amp;pjh) {  if (pjh.is_object()) {    std::cout \u0026lt;\u0026lt; \u0026quot;{\u0026quot;;    if (pjh.down()) {      pjh.print(std::cout); // must be a string      std::cout \u0026lt;\u0026lt; \u0026quot;:\u0026quot;;      pjh.next();      compute_dump(pjh); // let us recurse      while (pjh.next()) {        std::cout \u0026lt;\u0026lt; \u0026quot;,\u0026quot;;        pjh.print(std::cout);        std::cout \u0026lt;\u0026lt; \u0026quot;:\u0026quot;;        pjh.next();        compute_dump(pjh); // let us recurse      }      pjh.up();    }    std::cout \u0026lt;\u0026lt; \u0026quot;}\u0026quot;;  } else if (pjh.is_array()) {    std::cout \u0026lt;\u0026lt; \u0026quot;[\u0026quot;;    if (pjh.down()) {      compute_dump(pjh); // let us recurse      while (pjh.next()) {        std::cout \u0026lt;\u0026lt; \u0026quot;,\u0026quot;;        compute_dump(pjh); // let us recurse      }      pjh.up();    }    std::cout \u0026lt;\u0026lt; \u0026quot;]\u0026quot;;  } else {    pjh.print(std::cout); // just print the lone value  }}

下面的函数将找出所有的user.id整数:

void simdjson_traverse(std::vector\u0026lt;int64_t\u0026gt; \u0026amp;answer, ParsedJson::iterator \u0026amp;i) {  switch (i.get_type()) {  case '{':    if (i.down()) {      do {        bool founduser = equals(i.get_string(), \u0026quot;user\u0026quot;);        i.next(); // move to value        if (i.is_object()) {          if (founduser \u0026amp;\u0026amp; i.move_to_key(\u0026quot;id\u0026quot;)) {            if (i.is_integer()) {              answer.push_back(i.get_integer());            }            i.up();          }          simdjson_traverse(answer, i);        } else if (i.is_array()) {          simdjson_traverse(answer, i);        }      } while (i.next());      i.up();    }    break;  case '[':    if (i.down()) {      do {        if (i.is_object_or_array()) {          simdjson_traverse(answer, i);        }      } while (i.next());      i.up();    }    break;  case 'l':  case 'd':  case 'n':  case 't':  case 'f':  default:    break;  }}

深度比较

如果你想了解各种解析器如何验证给定的JSON文件:

make allparserscheckfile./allparserscheckfile myfile.json

性能比较:

make parsingcompetition./parsingcompetition myfile.json

更广泛的比较:

make allparsingcompetition./allparsingcompetition myfile.json

英文原文:https://github.com/lemire/simdjson

更多内容,请关注前端之巅。

每秒解析千兆字节的JSON解析器开源,秒杀一大波解析器!相关推荐

  1. flex bison解析json文件_每秒解析千兆字节的 JSON 解析器开源了

    本文转自我们的网站 InfoQ,译者无明.除了推荐 simdjson 之外,还想测试一下微信平台编辑器的代码样式功能. 事实证明,微信文章的代码展示能力很强了.非常棒. 近日,GitHub 开源了一 ...

  2. 双千兆和全千兆有什么区别?_千兆字节,太字节和PB有多少?

    双千兆和全千兆有什么区别? You've no doubt heard the terms gigabytes, terabytes, or petabytes thrown around befor ...

  3. 谢霆锋爱用的千元铁锅,在天猫国际俘获了一大波潮男

    你会花上千元的价格买一口炒菜用的铁锅吗? 这个问题如果放在五年前,估计大多数人会皱皱眉,然后回答:这太贵了.但是今天,越来越多的消费者愿意为生活中的小确幸买单,比如,拥有一口颜值和功能兼具的高端铁锅. ...

  4. 图像采集卡 | 以每秒千兆像素的速度进行图像处理

    以每秒千兆像素的速度进行图像处理 利用新型的处理硬件架构,以10至100 Gbit / s或更高的速度处理视频流. 背景 诸如3D成像,虚拟现实和广播之类的高级视觉系统依赖一个或多个高分辨率,高速相机 ...

  5. 千兆TCP拥塞控制算法分析

    作者:Geoff Huston,APNIC 回顾30多年来的互联网从业经验,我发现:促使互联网协议套件成功地成为全球通信系统首选技术的关键,是互联网协议(IP)本身.作为一种重叠协 议,它能够支持几乎 ...

  6. 网络猫只有计算机和机顶盒两个口,光猫为什么有千兆口和百兆口,两个不同的接口?二者有什么区别?...

    "极客谈科技",全新视角.全新思路,伴您遨游神奇的科技世界. 网络设备端口带宽采用的是十进制,比如较为原始的集线器,端口的容量一般为十兆,现在的光猫.路由器端口又分为了百兆.千兆端 ...

  7. 服务器千兆网卡显示百兆,windows10系统查看网卡是千兆还是百兆的方法

    在电脑中,通常是配备有网卡,而如今很多新主板配备的都是千兆网络接口,以更好的满足未来大宽带用户需求,但是许多windows10系统想要查看自己的电脑网卡是千兆还是百兆,却不知道要怎么操作,下面给大家讲 ...

  8. 兆比特每秒和兆字节每秒_比特 千比特 兆比特之间的换算

    http://help.360.cn/index.php?a=topic&bid=5030806&c=help&tid=19952261 时间内传输数据的平均比特数,其单位是比 ...

  9. 兆比特每秒和兆字节每秒_宽带中的“M(兆)”是什么意思?

    关于宽带,大家问的最多的问题之一,就是 "M(兆)" 是什么意思.本期的"到家"课堂就带大家了解一下! 什么是"兆"? 平时我们总说 50M ...

最新文章

  1. linux下编译onvif框架,Onvif第六课 Linux编译gsoap
  2. 突发!Intel CEO 换帅,VMware CEO 将走马上任
  3. 谈Objective-C Block的实现
  4. 人工智能技术类资源汇聚
  5. [转载]关于JAVA中子类和父类的构造方法
  6. 精妙SQL语句【转】
  7. SQL Server 中 GO 的用法
  8. java ireport动态报表_JasperReport学习笔记5-其它数据生成动态的报表(WEB)
  9. java设置界面边框,技术员教你解决Java 添加Word页面边框
  10. 【空间】C++内存管理
  11. 不一样的Office 365之 —— 使用Delve查看热门文档
  12. vue-cli3安装遇到的问题,卸载不掉旧版本,导致更新不了
  13. 常量、变量;基本数据类型;input()、if、while、break、continue
  14. C++ 类的封装继承多态
  15. TSP旅行商时间复杂度与空间复杂度
  16. c语言1到20联程,闫超
  17. 云服务器测速脚本_服务器性能自动化测试脚本
  18. Scrapy框架 - 学习日记2
  19. 工厂模式——简单工厂模式、工厂方法模式和抽象工厂模式
  20. 戴尔服务器ghost系统安装教程,戴尔台式机重装系统教程

热门文章

  1. 合资车忧“芯”忡忡,多款车型宣布停产,自主品牌的机会来了?
  2. it人都包括哪些岗位
  3. Android 多渠道打包配置,亲测,全集
  4. 电子商务网站建设策划书_电子商务网站建设方案:网站设计中网络营销功能不容忽视...
  5. 【机器学习】贝叶斯算法详解 + 公式推导 + 垃圾邮件过滤实战 + Python代码实现
  6. siRNA-S-S-PEG-LMWP|M-MSN-siRNA介孔二氧化硅修饰RNA(齐岳RNA功能化修饰)
  7. springboot整合swagger2,附带源码
  8. 键盘监听木马病毒原理
  9. 软件流程和管理(三):Risk Management
  10. sqlmap的使用方法