如何解决 Dart 解析大 Json 文件慢

2023-07-05 10:12:38 +08:00
 simman

最近在写 Flutter 应用,发现 Dart 解析比较大的 json 比较慢,会影响 UI 线程,使用 compute 的话,的确不影响 UI 线程了,但是解析起来更慢,想着可以使用 flutter rust bridge 做个 json 解析库,不过我用 rust 写个测试程序,发现解析 json 比 dart 快不了多少,各位有啥好意见没?

各语言测试:

time node index.js                           1.37s user 0.19s system 121% cpu 1.282 total
time go build && ./main                      1.59s user 0.02s system 80% cpu 2.002 total
time python3.9 main.py                       2.45s user 0.27s system 98% cpu 2.762 total
time cargo run --release                     2.46s user 0.42s system 97% cpu 2.972 total
time dart compile exe main.dart && bin/main  4.62s user 0.45s system 114% cpu 4.415 total

rust code:

use std::fs::File;
use std::io::{Read};

use serde_json::Value;

fn parse_json(contents: Vec<u8>) {
    let now = std::time::Instant::now();
    let _: Value = serde_json::from_slice(&contents).unwrap();
    let elapsed = now.elapsed();
    println!("elapsed: {:?}", elapsed);
}

fn main() {
    let contents = {
        let mut vec = Vec::new();
        // https://github.com/json-iterator/test-data/blob/master/large-file.json
        File::open("large-file.json").unwrap().read_to_end(&mut vec).unwrap();
        vec
    };
    for _ in 0..10 {
        parse_json(contents.clone());
    }
}

测试机器:MacBook Pro (16-inch, 2019) 2.3 GHz 八核 Intel Core i9 32 GB 2667 MHz DDR4

3654 次点击
所在节点    程序员
38 条回复
MoYi123
2023-07-05 10:28:46 +08:00
为什么要把编译的时间也算进去?
codehz
2023-07-05 10:32:43 +08:00
你可以考虑一下解析 json 的目的,如果可行的话,不需要先变成一个对象,而是直接从流式解析中提取需要的数据
simman
2023-07-05 10:36:44 +08:00
@MoYi123 go 、rust 、dart 实际是编译完后再 time 执行的。上面写的有问题。
newmlp
2023-07-05 10:40:36 +08:00
你这都把程序启动时间算上了,肯定不准啊,json 解析才能用多少时间估计 1ms 都不到
tool2d
2023-07-05 11:02:21 +08:00
纯好奇,用自己写的库解析了一下主贴里的 24M json ,竟然要 1 秒。

发现 dart 这些库,已经很强了。
wxf666
2023-07-05 11:03:48 +08:00
你要存啥呢?用个普通数据库也不错呀。。

比如,SQLite 解析 JSON 也挺快:

```
sqlite> .timer on
sqlite> SELECT json_array_length(readFile('large-file.json'));
11351
Run Time: real 0.089 user 0.046875 sys 0.046875
```
visper
2023-07-05 11:05:57 +08:00
rust 比 python 还慢.谁说 rust 快的
lisongeee
2023-07-05 11:07:15 +08:00
json 解析函数可以改成异步嘛?拆成多个子任务

let btachTaskNum = 0;
while(isParsing){
dobtachTask();
btachTaskNum++;
if(btachTaskNum%1000==0){
await nextTick()
}
}
tool2d
2023-07-05 11:07:36 +08:00
二楼说的也对,看具体使用目的,如果预处理一次,全部变成二进制数转节点,变成特定格式,载入和查询起来都是很快的。

你要暴力遍历巨量文本的 json ,速度上不去。要动态查询某些节点,速度还是可以提升一下的。
lisongeee
2023-07-05 11:09:19 +08:00
艹,我刚刚我回答不符合题意,当作没看见吧
tool2d
2023-07-05 11:17:24 +08:00
@lisongeee 其实可以优化成异步或者多线程版本,那个 large-file.json 结构和 csv 一样,一行行很有规律。

但是不是所有的 json 都能这样有规律的拆分,层次结构过于复杂,也没办法拆分。
iOCZ
2023-07-05 11:18:43 +08:00
1 秒都不到怎么能算慢呢
iOCZ
2023-07-05 11:19:05 +08:00
我们的人生是需要转圈圈的
debuggerx
2023-07-05 11:21:49 +08:00
数据量大的时候就应该考虑是不是不应该用 json
lisongeee
2023-07-05 11:47:04 +08:00
@tool2d 不需要有规律的拆分,可以按照解析的 字符数量 拆分就行

比如每解析 10000 个 char 就 await nextTick() 一次就行
tool2d
2023-07-05 11:51:20 +08:00
@lisongeee dark 又不是单线程,你异步拆分和楼主解析单独放在 compute 线程里,是一回事,没办法提速。

要提速只能多线程拆分,按照 10000 个字节拆,算法上不好设计。
duke807
2023-07-05 11:52:29 +08:00
不如弃用 json 改用和 json 类似但支持二进制的 msgpack
roundgis
2023-07-05 12:13:36 +08:00
@visper 處理 text python 並不慢 就算是慢的部分也用 c 重寫了
icyalala
2023-07-05 12:25:34 +08:00
你要用 C/C++ 的那些库比如 simdjson ,帖子里的 24M json 也就十几 ms
x77
2023-07-05 12:45:13 +08:00
- 异步解析
- 缓存(避免重复的解析)
- 减少 Json 的体积
- 改进设计,不用 Json 存储巨量数据

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/954190

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX