JSON 性能测试之二 - wastjson 每秒 6GB 解析速度完胜 simdjson-java!
前一篇JSON性能测试对比Fastjson2和DslJson,有评论提到和simdjson-java对比,那就测试走起.
说下simdjson-java这个库,之前也听说过,由于早前官网测试用的文本非常离谱,而且依赖JDK18+就没怎么关注,现在只要搜索simdjson(c++)基本上就能看到宣传最多的就是每秒千兆解析超越同类C++库甚至25倍的都有,不确定simdjson和simdjson-java性能差异有多大,下面只和simdjson-java做下对比测试。
测试环境: openJdk21 + window10 + i5 单线程
jvm参数: -Xms3g -Xmx3g --add-opens=java.base/java.time=ALL-UNNAMED --add-modules=jdk.incubator.vector
maven 依赖截止当前最新版本
<dependency> <groupId>org.simdjson</groupId> <artifactId>simdjson-java</artifactId> <version>0.3.0</version> </dependency> <dependency> <groupId>io.github.wycst</groupId> <artifactId>wast</artifactId> <version>0.0.19</version> </dependency> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-core</artifactId> <version>1.36</version> </dependency> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-generator-annprocess</artifactId> <version>1.36</version> </dependency>
场景测试一: 测试数据摘自simdjson-java官方(twitter.json内容已经相对正常多了),数据大小: 631kb
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import io.github.wycst.wast.common.utils.IOUtils; import io.github.wycst.wast.json.JSONNode; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.TimeValue; import org.simdjson.JsonValue; import org.simdjson.SimdJsonParser; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; /** * @Date 2024/11/24 15:46 * @Created by wangyc */ public class TwitterJmhTest { final static byte[] buffer; final static SimdJsonParser simdJsonParser = new SimdJsonParser(); static { try { buffer = IOUtils.readBytes(TwitterJmhTest.class.getResourceAsStream("/data/json/twitter.json")); System.out.println("data size: " + (buffer.length >> 10) + "kb"); } catch (Exception e) { throw new RuntimeException(e); } } // @Benchmark // public int parseAndSelect_Fastjson2() { // JSONObject jsonObject = (JSONObject) JSON.parse(buffer); // Set<String> defaultUsers = new HashSet<>(); // Iterator<Object> tweets = jsonObject.getJSONArray("statuses").iterator(); // while (tweets.hasNext()) { // JSONObject tweet = (JSONObject) tweets.next(); // JSONObject user = (JSONObject) tweet.get("user"); // if (user.getBoolean("default_profile")) { // defaultUsers.add(user.getString("screen_name")); // } // } // return defaultUsers.size(); // } // // @Benchmark // public int schemaBasedParseAndSelect_Fastjson2() { // Set<String> defaultUsers = new HashSet<>(); // SimdJsonTwitter twitter = JSON.parseObject(buffer, SimdJsonTwitter.class); // for (SimdJsonStatus status : twitter.statuses) { // SimdJsonUser user = status.user; // if (user.default_profile) { // defaultUsers.add(user.screen_name); // } // } // return defaultUsers.size(); // } @Benchmark public int parseAndSelect_WastJson() { List<JSONNode> users = JSONNode.collect(buffer, "/statuses/*/user"); Set<String> defaultUsers = new HashSet<>(); for (JSONNode user : users) { if (user.getChildValue("default_profile", boolean.class)) { defaultUsers.add(user.getChildValue("screen_name", String.class)); } } return defaultUsers.size(); } @Benchmark public int schemaBasedParseAndSelect_WastJson() { Set<String> defaultUsers = new HashSet<>(); SimdJsonTwitter twitter = io.github.wycst.wast.json.JSON.parseObject(buffer, SimdJsonTwitter.class); for (SimdJsonStatus status : twitter.statuses) { SimdJsonUser user = status.user; if (user.default_profile) { defaultUsers.add(user.screen_name); } } return defaultUsers.size(); } @Benchmark public int parseAndSelect_SimdjsonJava() { JsonValue simdJsonValue = simdJsonParser.parse(buffer, buffer.length); Set<String> defaultUsers = new HashSet<>(); Iterator<JsonValue> tweets = simdJsonValue.get("statuses").arrayIterator(); while (tweets.hasNext()) { JsonValue tweet = tweets.next(); JsonValue user = tweet.get("user"); if (user.get("default_profile").asBoolean()) { defaultUsers.add(user.get("screen_name").asString()); } } return defaultUsers.size(); } @Benchmark public int schemaBasedParseAndSelect_SimdjsonJava() { Set<String> defaultUsers = new HashSet<>(); SimdJsonTwitter twitter = simdJsonParser.parse(buffer, buffer.length, SimdJsonTwitter.class); for (SimdJsonStatus status : twitter.statuses()) { SimdJsonUser user = status.user(); if (user.default_profile()) { defaultUsers.add(user.screen_name()); } } return defaultUsers.size(); } record SimdJsonUser(boolean default_profile, String screen_name) { } record SimdJsonStatus(SimdJsonUser user) { } record SimdJsonTwitter(List<SimdJsonStatus> statuses) { } public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .include(TwitterJmhTest.class.getName()) .mode(Mode.Throughput) .warmupIterations(1) .warmupTime(TimeValue.seconds(3)) .measurementTime(TimeValue.seconds(3)) .forks(1) .threads(1) .build(); new Runner(options).run(); } }
测试结果(每秒运行次数)
Benchmark Mode Cnt Score Error Units TwitterJmhTest.parseAndSelect_SimdjsonJava thrpt 5 1370.652 ± 37.171 ops/s TwitterJmhTest.parseAndSelect_WastJson thrpt 5 1997.455 ± 275.386 ops/s TwitterJmhTest.schemaBasedParseAndSelect_SimdjsonJava thrpt 5 2092.163 ± 98.596 ops/s TwitterJmhTest.schemaBasedParseAndSelect_WastJson thrpt 5 2654.975 ± 102.240 ops/s
parseAndSelect: WastJson 大约是 SimdjsonJava的1.45倍(解析速度wast 1.23g/s, simdjson 0.84g/s)
schemaBasedParseAndSelect:WastJson大约是SimdjsonJava的1.26倍(解析速度wast 1.6g/s, simdjson 1.28g/s)
以上是在simdjson-java官方提供数据下,WastJson都能完胜.
场景测试二: 全部为ascii编码的字节数组,大小1464kb
测试代码
package com.jmh.test.simdjson; import io.github.wycst.wast.json.JSON; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.TimeValue; import org.simdjson.JsonValue; import org.simdjson.SimdJsonParser; import java.util.HashMap; import java.util.Map; /** * @Date 2024/11/27 * @Created by wangyc */ public class AsciiSourceJmhTest { final static byte[] buffer; final static SimdJsonParser simdJsonParser = new SimdJsonParser(); static { try { int length = 100000; StringBuilder value = new StringBuilder("a".repeat(length)); Map map = new HashMap(); map.put("a", value); map.put("b", value); map.put("c", value); map.put("d", value); map.put("e", value); map.put("f", value); map.put("g", value); map.put("h", value); map.put("i", value); map.put("j", value); map.put("k", value); map.put("l", value); map.put("m", value); map.put("n", value); map.put("o", value); buffer = io.github.wycst.wast.json.JSON.toJsonBytes(map); System.out.println("data size: " + (buffer.length >> 10) + "kb"); } catch (Exception e) { throw new RuntimeException(e); } } @Benchmark public long ascii_WastJson() { long result = 0; Map map = (Map) JSON.parse(buffer); result += map.get("a").toString().length(); result += map.get("b").toString().length(); result += map.get("c").toString().length(); result += map.get("d").toString().length(); result += map.get("e").toString().length(); result += map.get("f").toString().length(); result += map.get("g").toString().length(); result += map.get("h").toString().length(); result += map.get("i").toString().length(); result += map.get("j").toString().length(); result += map.get("k").toString().length(); result += map.get("l").toString().length(); result += map.get("m").toString().length(); result += map.get("n").toString().length(); result += map.get("o").toString().length(); return result; } @Benchmark public long ascii_SimdjsonJava() { long result = 0; JsonValue simdJsonValue = simdJsonParser.parse(buffer, buffer.length); result += simdJsonValue.get("a").asString().length(); result += simdJsonValue.get("b").asString().length(); result += simdJsonValue.get("c").asString().length(); result += simdJsonValue.get("d").asString().length(); result += simdJsonValue.get("e").asString().length(); result += simdJsonValue.get("f").asString().length(); result += simdJsonValue.get("g").asString().length(); result += simdJsonValue.get("h").asString().length(); result += simdJsonValue.get("i").asString().length(); result += simdJsonValue.get("j").asString().length(); result += simdJsonValue.get("k").asString().length(); result += simdJsonValue.get("l").asString().length(); result += simdJsonValue.get("m").asString().length(); result += simdJsonValue.get("n").asString().length(); result += simdJsonValue.get("o").asString().length(); return result; } public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .include(AsciiSourceJmhTest.class.getName()) .mode(Mode.Throughput) .warmupIterations(1) .warmupTime(TimeValue.seconds(3)) .measurementTime(TimeValue.seconds(3)) .forks(1) .threads(1) .build(); new Runner(options).run(); } }
测试结果(每秒运行次数)
Benchmark Mode Cnt Score Error Units AsciiSourceJmhTest.ascii_SimdjsonJava thrpt 5 1231.578 ± 682.959 ops/s AsciiSourceJmhTest.ascii_WastJson thrpt 5 4212.839 ± 2349.629 ops/s
该场景下WastJson是Simdjson的3.4倍(解析速度 wast: 6.16GB/s, simdjson 1.8GB/s)
以上测试均为个人电脑环境下面的测试,感兴趣的也可以下载代码测试,如果有专业人士能测试不同平台的性能差异万分感谢!
测试代码仓库: https://gitee.com/xiaoch0209/wast-jmh-test/tree/main-openjdk23/ (以上测试代码和测试结果都已上传)

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Spring Security 大小写敏感校验鉴权绕过风险
漏洞描述 Spring Security 是开源的身份验证和访问控制框架。 由于java语言中String.toLowerCase()、String.toUpperCase()方法与语言地区(Locale)相关,在Spring Security受影响版本中调用该方法进行鉴权判断时未指定Locale参数。导致在特定地区的系统环境中(如土耳其语),Spring Security中的大小写字母转换将出现不一致,可能导致鉴权规则被绕过。 在新版本中Spring Security通过指定转换时的locale参数避免不一致问题。 漏洞名称 Spring Security 大小写敏感校验鉴权绕过风险 漏洞类型 使用具有不一致性实现的函数 发现时间 2024-11-20 漏洞影响广度 - MPS编号 MPS-z0eg-x6fj CVE编号 CVE-2024-38827 CNVD编号 - 影响范围 org.springframework.security.oauth:spring-security-oauth2@[1.0.0.RELEASE, 2.5.2.RELEASE] org.springframe...
- 下一篇
Ai2 发布 OLMo 2:迄今为止最好的完全开放语言模型
由已故的微软联合创始人 Paul Allen 创立的非营利性 AI 研究机构 Ai2 (Allen Institute for AI) 最新发布了 OLMo 2 系列模型,这是该机构推出的“Open Language Model (OLMo)”系列的第二代模型。 第一个 OLMo 于今年 2 月份发布。与 Meta 的 Llama 系列不同的是,OLMo 2 符合 OSI 对开源 AI 的定义,这意味着用于其开发的工具和数据都是公开的,任何人都可以访问和使用。 “OLMo 2 是一系列完全开放的语言模型,从头到尾都采用开放且可访问的训练数据、开源训练代码、可重复的训练方案、透明的评估、中间检查点等进行开发。通过公开分享我们的数据、方案和发现,我们希望为开源社区提供发现新方法和创新方法所需的资源。” OLMo 2 系列包含了一套全新的 7B 和 13B 模型系列,使用多达 5T 个 token 进行训练。Ai2 声称,一系列基准测试表明 OLMo 2 7B 和 13B 是迄今为止最好的全开放模型,通常比同等大小的开放权重模型表现更好。 且与之前的 OLMo 0424 模型相比所有任务的性...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2全家桶,快速入门学习开发网站教程
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- 2048小游戏-低调大师作品
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS6,CentOS7官方镜像安装Oracle11G