Golang实验性JSON API新探索

Golang实验性JSON API新探索 今天博客文章的链接:

A new experimental Go API for JSON - The Go Programming Language

Go 1.25 引入了对 encoding/json/jsontext 和 encoding/json/v2 包的实验性支持。

作为一个每天每时每刻都与 JSON 打交道的人,这对我来说真的很有趣。我个人并不关心诸如拒绝无效 UTF-8 字符之类的事情,但我能看到新的 jsontext 包的用例:

jsontext 包提供了在语法层面与 JSON 交互的功能,其名称来源于 RFC 8259, section 2,其中 JSON 数据的语法字面意思就叫 JSON-text。由于它只在语法层面与 JSON 交互,因此不依赖于 Go 反射。

开箱即用,反序列化性能得到了极大提升:

v2Marshal 性能大致与 v1 持平。有时稍快一些,有时稍慢一些。v2Unmarshal 性能则显著快于 v1,基准测试显示性能提升高达 10 倍。

如果你实现一个新的接口,还可以启用流式处理:

为了获得更大的性能提升,现有的 MarshalerUnmarshaler 实现应该迁移到同时实现 MarshalerToUnmarshalerFrom,以便它们能够受益于以纯流式方式处理 JSON。例如,在 Kubernetes 的某个特定服务中,UnmarshalJSON 方法中对 OpenAPI 规范的递归解析严重影响了性能(参见 kubernetes/kube-openapi#315),而切换到 UnmarshalJSONFrom 则使性能提高了几个数量级。

我很有兴趣尝试一下,并希望它能早点出现。我即将启动一个项目,为现有的类似 MongoDB 的数据库 API 构建 Go 库,这听起来很适合我的项目。你们怎么看?


更多关于Golang实验性JSON API新探索的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang实验性JSON API新探索的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


encoding/json/v2 确实带来了显著的性能改进,特别是在反序列化方面。以下是几个关键点的示例代码:

  1. 基本使用
package main

import (
    "encoding/json/v2"
    "fmt"
)

type User struct {
    Name  string `json:"name"`
    Age   int    `json:"age"`
    Email string `json:"email"`
}

func main() {
    // 序列化
    user := User{Name: "Alice", Age: 30, Email: "alice@example.com"}
    data, _ := v2.Marshal(user)
    fmt.Println(string(data))
    
    // 反序列化
    jsonStr := `{"name":"Bob","age":25,"email":"bob@example.com"}`
    var user2 User
    v2.Unmarshal([]byte(jsonStr), &user2)
    fmt.Printf("%+v\n", user2)
}
  1. 流式处理接口实现
type CustomData struct {
    Value string
}

// 实现 MarshalerTo 接口
func (c CustomData) MarshalJSONTo(enc *v2.Encoder) error {
    return enc.WriteToken(v2.String(c.Value))
}

// 实现 UnmarshalerFrom 接口
func (c *CustomData) UnmarshalJSONFrom(dec *v2.Decoder) error {
    token, err := dec.ReadToken()
    if err != nil {
        return err
    }
    if str, ok := token.(v2.String); ok {
        c.Value = string(str)
    }
    return nil
}

func main() {
    data := CustomData{Value: "streaming example"}
    
    // 使用流式编码
    enc := v2.NewEncoder(io.Discard)
    data.MarshalJSONTo(enc)
    
    // 使用流式解码
    jsonStr := `"streaming example"`
    dec := v2.NewDecoder(strings.NewReader(jsonStr))
    var result CustomData
    result.UnmarshalJSONFrom(dec)
}
  1. jsontext 包的使用
import "encoding/json/jsontext"

func main() {
    // 语法层面的 JSON 操作
    jsonStr := `{"name": "test", "value": 42}`
    
    // 验证 JSON 语法
    if jsontext.Valid([]byte(jsonStr)) {
        fmt.Println("Valid JSON")
    }
    
    // 直接操作 JSON 令牌
    dec := jsontext.NewDecoder(strings.NewReader(jsonStr))
    for {
        token, err := dec.ReadToken()
        if err != nil {
            break
        }
        fmt.Printf("Token: %v\n", token)
    }
}
  1. 性能对比示例
func benchmarkUnmarshal(b *testing.B) {
    jsonData := []byte(`{"name":"test","items":[1,2,3,4,5]}`)
    
    b.Run("v1", func(b *testing.B) {
        for i := 0; i < b.N; i++ {
            var data map[string]interface{}
            json.Unmarshal(jsonData, &data)
        }
    })
    
    b.Run("v2", func(b *testing.B) {
        for i := 0; i < b.N; i++ {
            var data map[string]interface{}
            v2.Unmarshal(jsonData, &data)
        }
    })
}

对于数据库 API 库项目,v2 包的流式处理能力特别适合处理大型 JSON 文档。新的接口设计减少了内存分配,对于高频 JSON 处理场景能提供更好的性能表现。

回到顶部