simdjson 高性能JSON解析C++库
simdjson 是什么
simdjson 是一个用来解析JSON数据的 C++ 库,它使用常用的 SIMD 指令和微并行算法来每秒解析千兆字节的 JSON,在Velox, ClickHouse, Doris 中均有使用。
加载和解析 JSON documents
出于性能考虑,simdjson 需要一个末尾有几个字节(simdjson::SIMDJSON_PADDING)的字符串,这些字节可以被读取,但它们的内容不会影响解析。实际上,这意味着 JSON 输入应存储在末尾带有 simdjson::SIMDJSON_PADDING 额外字节的内存区域中。用户不需要对这些额外的字节指定值。
simdjson 库提供了一个类似树的 API,可以通过创建 ondemand::parser 并调用 iterate() 方法来访问它。 iterate() 方法可以快速索引输入字符串,并且可以检测到一些错误(JSON不合法)。以下是针对不同字符串表达方式的示例:
ondemand::parser parser;
auto json = padded_string::load("twitter.json"); // load JSON file 'twitter.json'.
ondemand::document doc = parser.iterate(json); // position a pointer at the beginning of the JSON data
ondemand::parser parser;
auto json = "[1,2,3]"_padded; // The _padded suffix creates a simdjson::padded_string instance
ondemand::document doc = parser.iterate(json); // parse a string
ondemand::parser parser;
char json[3+SIMDJSON_PADDING];
strcpy(json, "[1]");
ondemand::document doc = parser.iterate(json, strlen(json), sizeof(json));
std::string data = "my data";
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
建议不要在应用程序中创建许多 std::string 或许多 std::padding_string 实例来存储 JSON 数据,而是重用相同的缓冲区并限制内存分配。
Documents 就是迭代器
simdjson 解析JSON是按需的,document 并不是被完全解析后的JSON,他是一个用于迭代JSON文本的迭代器。当你在迭代时会触发解析原始的JSON文本,处理括号、逗号之类的分隔符,保证你能够得到结果。这么做对于性能提升非常关键,可以跳过不需要的解析动作
Parser, document 和 JSON的作用域
为了代码合法,需要在解析JSON时保证(1)parser 实例(2)输入的JSON string(3)document实例 都存活。并且要遵守以下两点:
- 一个 parser 实例同时最多有一个 document,因为它持有用于解析而分配的内存。
- 按照设计,每个JSON文档应该只有一个 document 实例。因此,如果必须将文档实例按引用传递给函数以避免复制,避免按值传递。
在 iterate 调用期间,原始 JSON 文本永远不会被修改——只能读取。用完 document 后,可以安全地丢弃数据源(无论是文件还是字符串)。
为了获得最佳性能,Parser实例应该在多个文件上重用:否则会不必要地重新分配内存,这是一个开销较大的过程。
如果需要同时解析多个 document,则应该有多个parser实例。
string_view
simdjson使用std::string_view表示已解析的字符串。string_view避免了复制数据的需要和以空字符结尾的C字符串的陷阱。它使用户更容易将数据复制到他们自己喜欢的类实例中。std::string_view 实例实际上只是指向内存中表示字符串的区域的指针。在 simdjson 中,我们返回 std::string_view 实例,这些实例要么指向您解析的输入字符串内或parser实例内的临时字符串缓冲区,该缓冲区在parser实例被销毁或使用它来解析另一个document之前一直有效。
使用解析后的 JSON
需要牢记以下规则:
- 当访问 document 时,document 实例应保留在作用域内:它是“迭代器”,用于跟踪您在 JSON 文档中的位置。根据设计,每个 JSON 文档有且仅有一个document实例。
- 因为 document 实际上只是一个迭代器,所以在访问同级对象或数组之前,您必须完全消耗当前对象或数组。
- 值只能使用一次,如果打算多次需要它们,应该获取并存储它们。应该只访问对象的键一次。应该只检查一次数组的值
以下具体说明指示如何在启用异常时使用 JSON:
-
校验使用的东西。调用iterate时,document 会被快速索引。如果它不是有效的Unicode(UTF-8)字符串,或者如果存在未关闭的字符串,则可能会立即报告错误。但是它没有完全验证整个JSON。仅完全验证被使用的值和相关结构。这意味着在遍历document的每一步,都可能遇到错误。可以处理带有异常或错误代码的错误。
-
提取值。可以将 JSON元素转换为 native type:double(element)。这适用于
std::string_view, double, uint64_t, int64_t, bool, ondemand::object and ondemand::array. 也有显示方法get_string(),get_double(),get_uint64(),get_int64(),get_bool(),get_object()andget_array(). 当调用显式或隐式的转换方法后,可能会抛出无法转换的异常。 -
字段访问。要获取对象中“foo”字段的值,请使用
object["foo"]。这将扫描对象,查找具有匹配字符串的字段,并进行逐个字符的比较。如果对象中没有这样的键,可能会生成错误 simdjson::NO_SUCH_FIELD,可能会抛出异常。为了获得最佳性能,应该尝试按照键在文档中出现的顺序来查询键。 -
输出成string。给定 JSON 文档中的文档、值、数组或对象,您可以输出适合再次解析为 JSON 内容的 JSON 字符串版本:
simdjson::to_json_string(element).对 to_json_string 的调用会完全consume该元素:如果将其应用于 document,则 JSON 指针将前进到document的末尾。to_json_string函数不应与获取字符串实例的值相混淆,该字符串实例是使用指向parser实例内的内部字符串缓冲区的轻量级 std::string_view 实例进行转义和表示的。为了说明这一点,以下两个代码段中的第一个将打印带有引号的未转义字符串“test”,而第二个代码段将打印字符串的转义内容(不带引号):test。// serialize a JSON to an escaped std::string instance so that it can be parsed again as JSON auto silly_json = R"( { "test": "result" } )"_padded; ondemand::document doc = parser.iterate(silly_json); std::cout << simdjson::to_json_string(doc["test"]) << std::endl; // Requires simdjson 1.0 or better// retrieves an unescaped string value as a string_view instance auto silly_json = R"( { "test": "result" } )"_padded; ondemand::document doc = parser.iterate(silly_json); std::cout << std::string_view(doc["test"]) << std::endl; -
还有一些其他的,详见官方文档
错误处理
默认情况下,simdjson 库会在出现错误时引发异常 (simdjson_error)。如果在代码中省略了 try-catch,未捕获的异常将停止程序,有两种方法处理错误,一是单个 try/catch 子句进行错误处理,二是使用无异常方法。
-
try/catch 子句进行错误处理
bool simple_error_example_except() {TEST_START();ondemand::parser parser;auto json = R"({"bad number":3.14.1 })"_padded;try {ondemand::document doc = parser.iterate(json);double x = doc["bad number"].get_double();std::cout << "Got " << x << std::endl;return true;} catch(simdjson_error& e) {// e.error() == NUMBER_ERRORstd::cout << e.error() << std::endl;return false;}} -
使用异常和单个 try/catch 子句进行错误处理使代码变得简单,但它使您无法控制错误。为了更轻松地调试或更强大的错误处理,您可能需要考虑使用无异常方法。整个 simdjson API 都可以使用无异常方法。所有可能失败的 simdjson API 都会返回 simdjson_result,它是一个 <value, error_code> 对。可以使用 .get() 检索值而不生成异常,如下所示:
ondemand::document doc; auto error = parser.iterate(json).get(doc); if (error) { cerr << error << endl; exit(1); }如果没有错误,则返回错误代码 simdjson::SUCCESS:它的计算结果为布尔值 false。有几个错误代码来指示错误,它们的计算结果为布尔值为 true。当使用无异常的API时,有责任在使用结果之前检查错误:如果有错误,结果值将无效,使用它将导致未定义的行为。
用一个例子来说明,我们尝试访问一个无效的值(3.14.1)。如果我们想继续而不抛出和捕获异常,我们可以这样做:
bool simple_error_example() {ondemand::parser parser;auto json = R"({"bad number":3.14.1 })"_padded;ondemand::document doc;if (parser.iterate(json).get(doc) != SUCCESS) { return false; }double x;auto error = doc["bad number"].get_double().get(x);// returns "simdjson::NUMBER_ERROR"if (error != SUCCESS) {std::cout << error << std::endl;return false;}std::cout << "Got " << x << std::endl;return true; }参考
https://github.com/simdjson/simdjson/blob/master/doc/basics.md
https://simdjson.org/
相关文章:
simdjson 高性能JSON解析C++库
simdjson 是什么 simdjson 是一个用来解析JSON数据的 C 库,它使用常用的 SIMD 指令和微并行算法来每秒解析千兆字节的 JSON,在Velox, ClickHouse, Doris 中均有使用。 加载和解析 JSON documents 出于性能考虑,simdjson 需要一个末尾有几个…...
安卓Context上下文
目录 前言一、Context简介二、Application Context2.1 Application Context的创建过程2.2 Application Context的获取过程 三、Activity的Context创建过程四、Service的Context创建过程 前言 Context也就是上下文对象,是Android较为常用的类,但是对于Co…...
实验13 简单拓扑BGP配置
实验13 简单拓扑BGP配置 一、 原理描述二、 实验目的三、 实验内容四、 实验配置五、 实验步骤 一、 原理描述 BGP(Border Gateway Protocol,边界网关协议)是一种用于自治系统间的动态路由协议,用于在自治系统(AS&…...
面试题分享--Spring02
Spring 框架中都用到了哪些设计模式?(必会) 1. 工厂模式:BeanFactory 就是简单工厂模式的体现,用来创建对象的实例 2. 单例模式:Bean 默认为单例模式 3. 代理模式:Spring 的 AOP 功能用到了 JDK 的动态代理和 CGLIB 字节码生成…...
基于QT和C++实现的中国象棋
一,源码 board.h #ifndef BOARD_H #define BOARD_H#include <QWidget> #include "Stone.h"class Board : public QWidget {Q_OBJECT public:explicit Board(QWidget *parent 0);bool _bRedTurn; // 红方先走int _currentPlayer; // 当前玩家&…...
Mojo崛起:AI-first 的编程语言能否成为新流行?
眨眼之间,你可能会错过又一种编程语言的发明。 有个笑话说,程序员花费20%的时间编写代码,80%的时间决定使用什么语言。 事实上,编程语言如此之多,以至于我们不确定实际有多少种。据估计,至少有700种编程语…...
【数据结构与算法】哈夫曼树与哈夫曼编码
文章目录 哈夫曼树(最优二叉树)定义举个🌰(WPL的计算) 哈夫曼树的构造(最优二叉树的构造)举个🌰 哈夫曼树的性质 哈夫曼编码定义构造 哈夫曼树(最优二叉树) …...
基于多头注意力机制卷积神经网络结合双向门控单元CNN-BIGRU-Mutilhead-Attention实现柴油机故障诊断附matlab代码
在使用这些深度学习库时,你可以按照以下步骤构建CNN-BIGRU-Multihead-Attention模型: 导入所需的库和模块。例如,在使用TensorFlow时,你可以导入tensorflow库和其他需要的模块。 定义输入层。根据你的数据,定义适当的…...
k8s redis 单节点部署
k8s redis 单节点部署kubectl 执行脚本 kubectl --kubeconfig ~/.kube-rz-real/config apply -f redis-leader.yaml -n rz-dt vi redis-leader.yamlapiVersion: apps/v1 kind: Deployment metadata:name: redis-leader-deploylabels:app: redisrole: leadertier: backend sp…...
科普童话投稿
《科普童话》杂志是由国家新闻出版总署批准、黑龙江省教育厅主管、黑龙江省语言文字报刊社主办的正规期刊。《科普童话》以培养科学素养与创新探索精神为办刊宗旨,以科学与艺术统一为编辑方针,以科学教育、教育科学作为自己的出发点,致力于对…...
【Ardiuno】使用ESP32单片机创建web服务通过网页控制小灯开关的实验(图文)
经过实验测试ESP32单片机的网络连接还是很方便的,这里小飞鱼按照程序实例的代码亲自实验一下使用Esp32生成的网页服务来实现远程无线控制小灯开关功能,这样真的是离物联网开发越来越近了,哈哈! 连接好开发板和电路,将…...
百元蓝牙耳机哪款音质最好?四款实力超群机型推荐
在蓝牙耳机市场竞争日益激烈的今天,百元级别的耳机已经具备了令人瞩目的音质表现,对于追求高性价比的消费者来说,如何在众多选项中挑选出一款音质卓越的蓝牙耳机,无疑是一项重要而又充满挑战的任务,今天我将为大家推荐…...
Linux系统之mtr命令的基本使用
Linux系统之mtr命令的基本使用 一、mtr命令介绍二、mtr命令使用帮助2.1 mtr命令的帮助信息2.2 mtr帮助信息解释 三、安装mtr工具四、mtr命令的基本使用4.1 直接使用4.2 设定ping次数4.3 禁用DNS解析4.4 显示IP地址4.5 调整间隔 五、总结 一、mtr命令介绍 mtr命令是一个网络诊断…...
实战tcpdump4.99.4交叉编译
主要是记录交叉编译的一个坑,不知道为什么网上的教程都没遇到过。 环境 libpcap 1.10.4tcpdump 4.99.4WSL 编译步骤 注意事项 注意解压的时候文件夹名需要是libpcap-1.10.4,由于我是在github直接下载zip的压缩包名是libpcap-libpcap-1.10.4.tar.gz解…...
重生奇迹MU召唤术师简介
出生地:幻术园 性 别:女 擅 长:召唤幻兽、辅助魔法&攻击魔法 转 职:召唤巫师(3转) 介 绍:从古代开始流传下来的高贵的血缘,为了种族纯正血缘的延续及特殊使用咒术的天赋&…...
神经网络模型---AlexNet
一、AlexNet 1.导入tensorflow库,这里给简称为tf库 import tensorflow as tf from tensorflow.keras import datasets, layers, modelsdatasets:是用于训练和测试机器学习模型的数据集合 layers:是构建神经网络模型的关键组成部分 models&a…...
corona渲染器与vray比哪个好?支持云渲染平台吗
在视觉渲染技术领域,V-Ray和Corona都以其卓越的性能和广泛应用赢得了高度评价。这两款渲染器各有其独特的优势,使得在它们之间做出选择并非易事。不同的应用场景和用户需求可能会让它们各自展现出不同的优势。 一、corona渲染器跟vray怎么样 在比较V-…...
每日一练:攻防世界:Ditf
这是难度1的题吗??? 拿到一个png图片,第一反应就是CRC爆破,结果还真的是高度被修改了 这里拿到一个字符串,提交flag结果发现不是,那么只可能是密钥之类的了 看看有没有压缩包,搜索…...
约瑟夫环递归算法详解与实现
一、引言 约瑟夫环问题是一个著名的理论问题,其背景是在古罗马时期,有n个犯人被围成一个圈,从第一个人开始报数,每次报到m的人将被处决,然后从下一个人开始重新报数,直到所有人都被处决。这个问题可以用递…...
互联网应用主流框架整合之构建REST风格的系统
REST(Representational State Transfer),中文译为“表述性状态转移”,是由Roy Fielding博士在他的博士论文中提出的一种软件架构风格,特别适用于网络应用的设计。REST不是一个标准,而是一种设计原则和约束集…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
