一个Go JSON解析库的性能测试

67 阅读2分钟

背景

最近在做一个数据处理的项目,需要解析大量的 JSON 数据。用 Go 标准库的 encoding/json 感觉性能不太够,就找了几个第三方库测试一下。

其中有个叫 FxJSON 的库,宣传说性能比标准库快很多倍。本来觉得可能是夸大宣传,但测试下来发现确实还不错,于是就果断点了Star

项目地址:github.com/icloudza/fx…

文档:icloudza.github.io/fxjson/

安装:

go get github.com/icloudza/fxjson

简单测试

写了个简单的测试程序:

package main

import (
    "encoding/json"
    "fmt"
    "time"
    "github.com/icloudza/fxjson"
)

func main() {
    jsonData := `{
        "users": [
            {"name": "张三", "age": 25, "active": true},
            {"name": "李四", "age": 30, "active": false},
            {"name": "王五", "age": 28, "active": true}
        ]
    }`
    
    iterations := 10000
    
    // 标准库测试
    start := time.Now()
    for i := 0; i < iterations; i++ {
        var data map[string]interface{}
        json.Unmarshal([]byte(jsonData), &data)
        
        users := data["users"].([]interface{})
        for _, user := range users {
            u := user.(map[string]interface{})
            _ = u["name"].(string)
            _ = int(u["age"].(float64))
            _ = u["active"].(bool)
        }
    }
    stdTime := time.Since(start)
    
    // FxJSON 测试
    start = time.Now()
    for i := 0; i < iterations; i++ {
        node := fxjson.FromString(jsonData)
        
        node.Get("users").ArrayForEach(func(index int, user fxjson.Node) bool {
            _ = user.Get("name").StringOr("")
            _ = user.Get("age").IntOr(0)
            _ = user.Get("active").BoolOr(false)
            return true
        })
    }
    fxTime := time.Since(start)
    
    fmt.Printf("标准库: %v\n", stdTime)
    fmt.Printf("FxJSON: %v\n", fxTime)
    fmt.Printf("提升: %.1f倍\n", float64(stdTime)/float64(fxTime))
}

测试结果:

标准库: 89.2ms
FxJSON: 4.1ms
提升: 21.8倍

在这个场景下确实快了不少。

基本用法

API 设计比较直观:

// 解析 JSON
node := fxjson.FromString(jsonStr)
// 或者
node := fxjson.FromBytes(jsonBytes)

// 获取值,带默认值
name := node.Get("name").StringOr("默认名称")
age := node.Get("age").IntOr(0)
active := node.Get("active").BoolOr(false)

// 路径访问
email := node.GetPath("user.profile.email").StringOr("")

// 数组遍历
node.Get("items").ArrayForEach(func(index int, item fxjson.Node) bool {
    fmt.Printf("第%d项: %s\n", index, item.Get("name").StringOr(""))
    return true // 返回false可以终止遍历
})

实际使用

在项目中试用了一下:

配置文件读取

configBytes, _ := os.ReadFile("config.json")
config := fxjson.FromBytes(configBytes)

dbHost := config.GetPath("database.host").StringOr("localhost")
dbPort := config.GetPath("database.port").IntOr(3306)
redisEnabled := config.GetPath("redis.enabled").BoolOr(false)

比起定义结构体然后 json.Unmarshal,这种方式更灵活一些。

API 响应处理

resp, _ := http.Get("https://api.example.com/users")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)

data := fxjson.FromBytes(body)
total := data.GetPath("meta.total").IntOr(0)

var userNames []string
data.Get("data").ArrayForEach(func(i int, user fxjson.Node) bool {
    if user.Get("status").StringOr("") == "active" {
        userNames = append(userNames, user.Get("name").StringOr(""))
    }
    return true
})

性能特点

从文档看,主要的性能优化点:

  1. 减少内存分配。标准库需要创建很多 interface{} 和 map,FxJSON 直接在原始数据上操作
  2. 有缓存机制。重复访问相同路径时会更快
  3. 数组遍历做了优化

官方给的 benchmark 数据比较夸张,实际使用中提升程度取决于具体场景。处理大量数据时确实有明显改善。

一些注意点

  1. 错误处理方式不同。标准库会返回 error,这个库用默认值的方式处理
  2. 如果需要严格的类型检查,可能还是标准库更合适
  3. 对于简单场景,可能感受不到太大差别

总结

如果项目中有大量 JSON 处理,特别是性能敏感的场景,这个库值得试试。API 用起来比较方便,性能也确实有提升。

当然,选择什么库还是要根据具体需求。如果对性能要求不高,标准库其实也够用。