영어 | 중국어
JIT(Just-In-Time 컴파일) 및 SIMD(단일 명령 다중 데이터)로 가속화된 엄청나게 빠른 JSON 직렬화 및 역직렬화 라이브러리입니다.
go.dev를 참조하세요
모든 크기 의 json과 모든 사용 시나리오 에서 Sonic은 최고의 성능을 발휘합니다 .
goversion: 1.17 . 1
goos: darwin
goarch: amd64
cpu: Intel(R) Core(TM) i9 - 9880H CPU @ 2. 30GHz
BenchmarkEncoder_Generic_Sonic - 16 32393 ns / op 402.40 MB / s 11965 B / op 4 allocs / op
BenchmarkEncoder_Generic_Sonic_Fast - 16 21668 ns / op 601.57 MB / s 10940 B / op 4 allocs / op
BenchmarkEncoder_Generic_JsonIter - 16 42168 ns / op 309.12 MB / s 14345 B / op 115 allocs / op
BenchmarkEncoder_Generic_GoJson - 16 65189 ns / op 199.96 MB / s 23261 B / op 16 allocs / op
BenchmarkEncoder_Generic_StdLib - 16 106322 ns / op 122.60 MB / s 49136 B / op 789 allocs / op
BenchmarkEncoder_Binding_Sonic - 16 6269 ns / op 2079.26 MB / s 14173 B / op 4 allocs / op
BenchmarkEncoder_Binding_Sonic_Fast - 16 5281 ns / op 2468.16 MB / s 12322 B / op 4 allocs / op
BenchmarkEncoder_Binding_JsonIter - 16 20056 ns / op 649.93 MB / s 9488 B / op 2 allocs / op
BenchmarkEncoder_Binding_GoJson - 16 8311 ns / op 1568.32 MB / s 9481 B / op 1 allocs / op
BenchmarkEncoder_Binding_StdLib - 16 16448 ns / op 792.52 MB / s 9479 B / op 1 allocs / op
BenchmarkEncoder_Parallel_Generic_Sonic - 16 6681 ns / op 1950.93 MB / s 12738 B / op 4 allocs / op
BenchmarkEncoder_Parallel_Generic_Sonic_Fast - 16 4179 ns / op 3118.99 MB / s 10757 B / op 4 allocs / op
BenchmarkEncoder_Parallel_Generic_JsonIter - 16 9861 ns / op 1321.84 MB / s 14362 B / op 115 allocs / op
BenchmarkEncoder_Parallel_Generic_GoJson - 16 18850 ns / op 691.52 MB / s 23278 B / op 16 allocs / op
BenchmarkEncoder_Parallel_Generic_StdLib - 16 45902 ns / op 283.97 MB / s 49174 B / op 789 allocs / op
BenchmarkEncoder_Parallel_Binding_Sonic - 16 1480 ns / op 8810.09 MB / s 13049 B / op 4 allocs / op
BenchmarkEncoder_Parallel_Binding_Sonic_Fast - 16 1209 ns / op 10785.23 MB / s 11546 B / op 4 allocs / op
BenchmarkEncoder_Parallel_Binding_JsonIter - 16 6170 ns / op 2112.58 MB / s 9504 B / op 2 allocs / op
BenchmarkEncoder_Parallel_Binding_GoJson - 16 3321 ns / op 3925.52 MB / s 9496 B / op 1 allocs / op
BenchmarkEncoder_Parallel_Binding_StdLib - 16 3739 ns / op 3486.49 MB / s 9480 B / op 1 allocs / op
BenchmarkDecoder_Generic_Sonic - 16 66812 ns / op 195.10 MB / s 57602 B / op 723 allocs / op
BenchmarkDecoder_Generic_Sonic_Fast - 16 54523 ns / op 239.07 MB / s 49786 B / op 313 allocs / op
BenchmarkDecoder_Generic_StdLib - 16 124260 ns / op 104.90 MB / s 50869 B / op 772 allocs / op
BenchmarkDecoder_Generic_JsonIter - 16 91274 ns / op 142.81 MB / s 55782 B / op 1068 allocs / op
BenchmarkDecoder_Generic_GoJson - 16 88569 ns / op 147.17 MB / s 66367 B / op 973 allocs / op
BenchmarkDecoder_Binding_Sonic - 16 32557 ns / op 400.38 MB / s 28302 B / op 137 allocs / op
BenchmarkDecoder_Binding_Sonic_Fast - 16 28649 ns / op 455.00 MB / s 24999 B / op 34 allocs / op
BenchmarkDecoder_Binding_StdLib - 16 111437 ns / op 116.97 MB / s 10576 B / op 208 allocs / op
BenchmarkDecoder_Binding_JsonIter - 16 35090 ns / op 371.48 MB / s 14673 B / op 385 allocs / op
BenchmarkDecoder_Binding_GoJson - 16 28738 ns / op 453.59 MB / s 22039 B / op 49 allocs / op
BenchmarkDecoder_Parallel_Generic_Sonic - 16 12321 ns / op 1057.91 MB / s 57233 B / op 723 allocs / op
BenchmarkDecoder_Parallel_Generic_Sonic_Fast - 16 10644 ns / op 1224.64 MB / s 49362 B / op 313 allocs / op
BenchmarkDecoder_Parallel_Generic_StdLib - 16 57587 ns / op 226.35 MB / s 50874 B / op 772 allocs / op
BenchmarkDecoder_Parallel_Generic_JsonIter - 16 38666 ns / op 337.12 MB / s 55789 B / op 1068 allocs / op
BenchmarkDecoder_Parallel_Generic_GoJson - 16 30259 ns / op 430.79 MB / s 66370 B / op 974 allocs / op
BenchmarkDecoder_Parallel_Binding_Sonic - 16 5965 ns / op 2185.28 MB / s 27747 B / op 137 allocs / op
BenchmarkDecoder_Parallel_Binding_Sonic_Fast - 16 5170 ns / op 2521.31 MB / s 24715 B / op 34 allocs / op
BenchmarkDecoder_Parallel_Binding_StdLib - 16 27582 ns / op 472.58 MB / s 10576 B / op 208 allocs / op
BenchmarkDecoder_Parallel_Binding_JsonIter - 16 13571 ns / op 960.51 MB / s 14685 B / op 385 allocs / op
BenchmarkDecoder_Parallel_Binding_GoJson - 16 10031 ns / op 1299.51 MB / s 22111 B / op 49 allocs / op
BenchmarkGetOne_Sonic - 16 3276 ns / op 3975.78 MB / s 24 B / op 1 allocs / op
BenchmarkGetOne_Gjson - 16 9431 ns / op 1380.81 MB / s 0 B / op 0 allocs / op
BenchmarkGetOne_Jsoniter - 16 51178 ns / op 254.46 MB / s 27936 B / op 647 allocs / op
BenchmarkGetOne_Parallel_Sonic - 16 216.7 ns / op 60098.95 MB / s 24 B / op 1 allocs / op
BenchmarkGetOne_Parallel_Gjson - 16 1076 ns / op 12098.62 MB / s 0 B / op 0 allocs / op
BenchmarkGetOne_Parallel_Jsoniter - 16 17741 ns / op 734.06 MB / s 27945 B / op 647 allocs / op
BenchmarkSetOne_Sonic - 16 9571 ns / op 1360.61 MB / s 1584 B / op 17 allocs / op
BenchmarkSetOne_Sjson - 16 36456 ns / op 357.22 MB / s 52180 B / op 9 allocs / op
BenchmarkSetOne_Jsoniter - 16 79475 ns / op 163.86 MB / s 45862 B / op 964 allocs / op
BenchmarkSetOne_Parallel_Sonic - 16 850.9 ns / op 15305.31 MB / s 1584 B / op 17 allocs / op
BenchmarkSetOne_Parallel_Sjson - 16 18194 ns / op 715.77 MB / s 52247 B / op 9 allocs / op
BenchmarkSetOne_Parallel_Jsoniter - 16 33560 ns / op 388.05 MB / s 45892 B / op 964 allocs / op
BenchmarkLoadNode / LoadAll() -16 11384 ns / op 1143.93 MB / s 6307 B / op 25 allocs / op
BenchmarkLoadNode_Parallel / LoadAll() -16 5493 ns / op 2370.68 MB / s 7145 B / op 25 allocs / op
BenchmarkLoadNode / Interface() -16 17722 ns / op 734.85 MB / s 13323 B / op 88 allocs / op
BenchmarkLoadNode_Parallel / Interface() -16 10330 ns / op 1260.70 MB / s 15178 B / op 88 allocs / op
벤치마크 코드는 bench.sh를 참조하세요.
소개.md를 참조하세요.
기본 동작은 RFC8259를 준수 하지 않는 HTML 이스케이프 형식(Escape HTML 참조) 및 SortKeys
기능(선택적 지원은 Sort Keys 참조)을 제외하고 encoding/json
과 대부분 일치합니다.
import "github.com/bytedance/sonic"
var data YourSchema
// Marshal
output , err := sonic . Marshal ( & data )
// Unmarshal
err := sonic . Unmarshal ( output , & data )
Sonic은 io.Reader
에서 json을 디코딩하거나 io.Writer
로 개체를 인코딩하는 것을 지원하며, 여러 값을 처리하고 메모리 소비를 줄이는 것을 목표로 합니다.
var o1 = map [ string ] interface {}{
"a" : "b" ,
}
var o2 = 1
var w = bytes . NewBuffer ( nil )
var enc = sonic . ConfigDefault . NewEncoder ( w )
enc . Encode ( o1 )
enc . Encode ( o2 )
fmt . Println ( w . String ())
// Output:
// {"a":"b"}
// 1
var o = map [ string ] interface {}{}
var r = strings . NewReader ( `{"a":"b"}{"1":"2"}` )
var dec = sonic . ConfigDefault . NewDecoder ( r )
dec . Decode ( & o )
dec . Decode ( & o )
fmt . Printf ( "%+v" , o )
// Output:
// map[1:2 a:b]
import "github.com/bytedance/sonic/decoder"
var input = `1`
var data interface {}
// default float64
dc := decoder . NewDecoder ( input )
dc . Decode ( & data ) // data == float64(1)
// use json.Number
dc = decoder . NewDecoder ( input )
dc . UseNumber ()
dc . Decode ( & data ) // data == json.Number("1")
// use int64
dc = decoder . NewDecoder ( input )
dc . UseInt64 ()
dc . Decode ( & data ) // data == int64(1)
root , err := sonic . GetFromString ( input )
// Get json.Number
jn := root . Number ()
jm := root . InterfaceUseNumber ().(json. Number ) // jn == jm
// Get float64
fn := root . Float64 ()
fm := root . Interface ().( float64 ) // jn == jm
정렬로 인한 성능 손실(약 10%) 때문에 Sonic은 기본적으로 이 기능을 활성화하지 않습니다. 구성 요소가 작동하는 데 의존하는 경우(예: zstd) 다음과 같이 사용하십시오.
import "github.com/bytedance/sonic"
import "github.com/bytedance/sonic/encoder"
// Binding map only
m := map [ string ] interface {}{}
v , err := encoder . Encode ( m , encoder . SortMapKeys )
// Or ast.Node.SortKeys() before marshal
var root := sonic. Get ( JSON )
err := root . SortKeys ()
성능 손실(약 15%)로 인해 Sonic은 기본적으로 이 기능을 활성화하지 않습니다. encoder.EscapeHTML
옵션을 사용하여 이 기능을 열 수 있습니다( encoding/json.HTMLEscape
에 맞춰 정렬).
import "github.com/bytedance/sonic"
v := map [ string ] string { "&&" : "<>" }
ret , err := Encode ( v , EscapeHTML ) // ret == `{"u0026u0026":{"X":"u003cu003e"}}`
Sonic은 json.RawMessage
또는 json.Marshaler
마샬링을 제외하고 기본 개체(구조체/맵...)를 압축 형식 JSON으로 인코딩합니다. Sonic은 출력 JSON의 유효성을 검사하지만 성능 문제를 위해 압축 하지 않습니다 . 압축 프로세스를 추가하기 위해 옵션 encoder.CompactMarshaler
제공합니다.
입력 JSON에 유효하지 않은 구문이 있는 경우 Sonic은 오류 위치의 예쁜 인쇄를 지원하는 decoder.SyntaxError
반환합니다.
import "github.com/bytedance/sonic"
import "github.com/bytedance/sonic/decoder"
var data interface {}
err := sonic . UnmarshalString ( "[[[}]]" , & data )
if err != nil {
/* One line by default */
println ( e . Error ()) // "Syntax error at index 3: invalid charnnt[[[}]]nt...^..n"
/* Pretty print */
if e , ok := err .(decoder. SyntaxError ); ok {
/*Syntax error at index 3: invalid char
[[[}]]
...^..
*/
print ( e . Description ())
} else if me , ok := err .( * decoder. MismatchTypeError ); ok {
// decoder.MismatchTypeError is new to Sonic v1.6.0
print ( me . Description ())
}
}
특정 키에 대해 불일치 유형의 값이 있는 경우 Sonic은 decoder.MismatchTypeError
보고하지만(많은 경우 마지막 오류를 보고) 여전히 잘못된 값을 건너뛰고 다음 JSON을 계속 디코딩합니다.
import "github.com/bytedance/sonic"
import "github.com/bytedance/sonic/decoder"
var data = struct {
A int
B int
}{}
err := UnmarshalString ( `{"A":"1","B":1}` , & data )
println ( err . Error ()) // Mismatch type int with value string "at index 5: mismatched type with valuennt{"A":"1","B":1}nt.....^.........n"
fmt . Printf ( "%+v" , data ) // {A:0 B:1}
Sonic/ast.Node는 완전히 독립적인 JSON용 AST입니다. 직렬화와 역직렬화를 모두 구현하고 일반 데이터를 얻고 수정하기 위한 강력한 API를 제공합니다.
음수가 아닌 정수, 문자열 또는 nil이어야 하는 지정된 경로로 부분 JSON을 검색합니다.
import "github.com/bytedance/sonic"
input := [] byte ( `{"key1":[{},{"key2":{"key3":[1,2,3]}}]}` )
// no path, returns entire json
root , err := sonic . Get ( input )
raw := root . Raw () // == string(input)
// multiple paths
root , err := sonic . Get ( input , "key1" , 1 , "key2" )
sub := root . Get ( "key3" ). Index ( 2 ). Int64 () // == 3
팁 : Index()
오프셋을 사용하여 데이터를 찾기 때문에 Get()
과 같은 스캔보다 훨씬 빠르므로 최대한 많이 사용하는 것이 좋습니다. 또한 Sonic은 기본 사용 오프셋에 대한 또 다른 API IndexOrGet()
제공하고 키가 일치하는지 확인합니다.
Searcher
사용자가 다양한 요구 사항을 충족할 수 있도록 몇 가지 옵션을 제공합니다.
opts := ast. SearchOption { CopyReturn : true ... }
val , err := sonic . GetWithOptions ( JSON , opts , "key" )
ast.Node
Lazy-Load
설계를 사용하므로 기본적으로 Concurrently-Read를 지원하지 않습니다. 동시에 읽으시려면 지정해주세요.Set()/Unset()으로 json 콘텐츠 수정
import "github.com/bytedance/sonic"
// Set
exist , err := root . Set ( "key4" , NewBool ( true )) // exist == false
alias1 := root . Get ( "key4" )
println ( alias1 . Valid ()) // true
alias2 := root . Index ( 1 )
println ( alias1 == alias2 ) // true
// Unset
exist , err := root . UnsetByIndex ( 1 ) // exist == true
println ( root . Get ( "key4" ). Check ()) // "value not exist"
ast.Node
json으로 인코딩하려면 MarshalJson()
또는 json.Marshal()
사용하십시오(노드의 포인터를 전달해야 함).
import (
"encoding/json"
"github.com/bytedance/sonic"
)
buf , err := root . MarshalJson ()
println ( string ( buf )) // {"key1":[{},{"key2":{"key3":[1,2,3]}}]}
exp , err := json . Marshal ( & root ) // WARN: use pointer
println ( string ( buf ) == string ( exp )) // true
Check()
, Error()
, Valid()
, Exist()
Index()
, Get()
, IndexPair()
, IndexOrGet()
, GetByPath()
Int64()
, Float64()
, String()
, Number()
, Bool()
, Map[UseNumber|UseNode]()
, Array[UseNumber|UseNode]()
, Interface[UseNumber|UseNode]()
NewRaw()
, NewNumber()
, NewNull()
, NewBool()
, NewString()
, NewObject()
, NewArray()
Values()
, Properties()
, ForEach()
, SortKeys()
Set()
, SetByIndex()
, Add()
Sonic은 중간 표현( ast.Node
또는 interface{}
)을 사용하지 않고 JSON을 비표준 유형( map[string]interface{}
가 아닌 struct
도 아님)으로 완전히 구문 분석하기 위한 고급 API를 제공합니다. 예를 들어, interface{}
와 유사하지만 실제로는 interface{}
아닌 다음과 같은 유형이 있을 수 있습니다.
type UserNode interface {}
// the following types implement the UserNode interface.
type (
UserNull struct {}
UserBool struct { Value bool }
UserInt64 struct { Value int64 }
UserFloat64 struct { Value float64 }
UserString struct { Value string }
UserObject struct { Value map [ string ] UserNode }
UserArray struct { Value [] UserNode }
)
Sonic은 JSON AST의 선주문 순회를 반환하기 위해 다음 API를 제공합니다. ast.Visitor
는 일부 C++ JSON 라이브러리에서 사용되는 SAX 스타일 인터페이스입니다. ast.Visitor
직접 구현하고 ast.Preorder()
메서드에 전달해야 합니다. 방문자에서 JSON 값을 나타내는 사용자 정의 유형을 만들 수 있습니다. 개체/배열 계층 구조를 기록하기 위해 방문자에 O(n) 공간 컨테이너(예: 스택)가 있을 수 있습니다.
func Preorder ( str string , visitor Visitor , opts * VisitorOptions ) error
type Visitor interface {
OnNull () error
OnBool ( v bool ) error
OnString ( v string ) error
OnInt64 ( v int64 , n json. Number ) error
OnFloat64 ( v float64 , n json. Number ) error
OnObjectBegin ( capacity int ) error
OnObjectKey ( key string ) error
OnObjectEnd () error
OnArrayBegin ( capacity int ) error
OnArrayEnd () error
}
자세한 사용법은 ast/visitor.go를 참조하세요. 또한 ast/visitor_test.go에서 UserNode
에 대한 데모 방문자를 구현합니다.
다양한 시나리오를 충족하기 위해 Sonic을 사용하려는 개발자를 위해 우리는 sonic.API
로 일부 통합 구성을 제공합니다.
ConfigDefault
: Sonic의 기본 구성( EscapeHTML=false
, SortKeys=false
...)은 Sonic을 빠르게 실행하는 동시에 보안을 보장합니다.ConfigStd
: 표준 호환 구성( EscapeHTML=true
, SortKeys=true
...)ConfigFastest
: Sonic에서 최대한 빠르게 실행되는 가장 빠른 구성( NoQuoteTextMarshaler=true
)입니다. Sonic은 고성능 코드 개발의 어려움으로 인해 모든 환경 지원을 보장 하지 않습니다 . Sonic을 지원하지 않는 환경에서는 구현이 encoding/json
으로 대체됩니다. 따라서 beflow 구성은 모두 ConfigStd
와 동일합니다. Sonic은 런타임 컴파일에 그다지 적합하지 않은 JIT 어셈블러로 golang-asm을 사용하므로 거대한 스키마를 처음 실행하면 요청 시간 초과 또는 심지어 프로세스 OOM이 발생할 수 있습니다. 안정성을 높이려면 Marshal()/Unmarshal()
이전에 대규모 스키마 또는 소형 메모리 애플리케이션에 Pretouch()
사용하는 것이 좋습니다.
import (
"reflect"
"github.com/bytedance/sonic"
"github.com/bytedance/sonic/option"
)
func init () {
var v HugeStruct
// For most large types (nesting depth <= option.DefaultMaxIn