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不是一个标准,而是一种设计原则和约束集…...

vue3-自定义指令来实现input框输入限制
文章目录 前言具体实现分析主要部分详细解析导入和类型定义mounted 钩子函数unmounted 钩子函数指令注册使用 总结 前言 使用vue中的自定义指令来实现input框输入限制 其中关键代码强制触发input ,来避免,输入规则外的字符时,没触发vue的响…...

MySQL日志——redolog
redo log(重做日志) 为什么需要redo log? 在mysql提交一个事务后,这个事务所作的数据修改并不会直接保存到磁盘文件中,而是先保存在buffer pool缓冲区中,在需要读取数据时,先从缓冲区中找&…...

Python热涨落流体力学求解算法和英伟达人工智能核评估模型
🎯要点 🎯平流扩散简单离散微分算子 | 🎯相场模拟:简单旋节线分解、枝晶凝固的 | 🎯求解二维波动方程,离散化时间导数 🎯英伟达 A100 人工智能核性能评估模型 | 🎯热涨落流体动力学…...

【C语言】数组参数和指针参数详解
在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢? 1 一维数组传参 #include <stdio.h> void test(int arr[])//ok? {} void test(int arr[10])//ok? {} void test(int* arr)//ok? {} void test2(int* arr[20])…...

Tuple 元组
文章目录 一、什么是元组 ?二、元组的具体操作2.1 创建元组2.1.1 tuple() 创建元组函数和 list() 创建列表函数总结 2.2 元组的元素访问操作2.3 元组的元素计数操作2.4 zip 对象 一、什么是元组 ? 列表属于可变序列,可以任意修改列表中的元素。 元组的…...

(资料收藏)王阳明传《知行合一》共74讲,王阳明知行合一音频讲解资料
今天给大家带来的不是软件,而是一份精神食粮——《知行合一》的教程福利。这可不是一般的教程,它关乎心灵,关乎智慧,关乎我们如何在纷繁复杂的世界中找到自己的位置。 咱们得聊聊王阳明,这位明代的大儒,他…...

空气质量预报模式系统WRF-CMAQ
空气污染问题日益受到各级政府以及社会公众的高度重视,从实时的数据监测公布到空气质量数值预报及预报产品的发布,我国在空气质量监测和预报方面取得了一定进展。随着计算机技术的高速发展、空气污染监测手段的提高和人们对大气物理化学过程认识的深入&a…...

Collections.sort()方法总结
Collections.sort()方法总结 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们来探讨 Java 中的 Collections.sort() 方法。这个方法是 Java 集合框架中的…...

Java23种设计模式(二)
1、单例模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有…...

Web前端收入来源:探索多元化的盈利渠道
Web前端收入来源:探索多元化的盈利渠道 在数字化时代,Web前端技术日益成为推动互联网业务发展的重要力量。对于前端开发者而言,除了传统的薪资收入外,还存在多种潜在的收入来源。本文将从四个方面、五个方面、六个方面和七个方面…...