อังกฤษ | 中文
ไลบรารีการทำให้ซีเรียลไลซ์และดีซีเรียลไลซ์ JSON ที่รวดเร็วอย่างเห็นได้ชัด เร่งความเร็วโดย JIT (การคอมไพล์แบบทันเวลา) และ SIMD (คำสั่งเดียว-หลายข้อมูล)
ดู 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.
พฤติกรรมเริ่มต้นส่วนใหญ่จะสอดคล้องกับ encoding/json
ยกเว้นรูปแบบการหลบหนี HTML (ดู Escape HTML) และคุณลักษณะ SortKeys
(การสนับสนุนเพิ่มเติม ดูที่ คีย์การเรียงลำดับ) ที่ ไม่ สอดคล้องกับ RFC8259
import "github.com/bytedance/sonic"
var data YourSchema
// Marshal
output , err := sonic . Marshal ( & data )
// Unmarshal
err := sonic . Unmarshal ( output , & data )
Sonic รองรับการถอดรหัส json จาก io.Reader
หรือการเข้ารหัสออบเจ็กต์ลงใน 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%) โซนิคจึงไม่เปิดใช้งานคุณสมบัตินี้ตามค่าเริ่มต้น หากส่วนประกอบของคุณขึ้นอยู่กับการทำงาน (เช่น 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%) โซนิคจึงไม่เปิดใช้งานคุณสมบัตินี้ตามค่าเริ่มต้น คุณสามารถใช้ตัวเลือก encoder.EscapeHTML
เพื่อเปิดฟีเจอร์นี้ (สอดคล้องกับ encoding/json.HTMLEscape
)
import "github.com/bytedance/sonic"
v := map [ string ] string { "&&" : "<>" }
ret , err := Encode ( v , EscapeHTML ) // ret == `{"u0026u0026":{"X":"u003cu003e"}}`
Sonic เข้ารหัสวัตถุดั้งเดิม (struct/map...) เป็น JSON รูปแบบกะทัดรัดตามค่าเริ่มต้น ยกเว้น marshaling json.RawMessage
หรือ json.Marshaler
: 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 เป็น AST ที่สมบูรณ์ในตัวเองสำหรับ JSON โดยจะใช้ทั้งการทำให้ซีเรียลไลซ์และดีซีเรียลไลซ์ และจัดเตรียม API ที่มีประสิทธิภาพสำหรับการรับและแก้ไขข้อมูลทั่วไป
ค้นหา 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()
มาก เราขอแนะนำให้คุณใช้มันให้มากที่สุด และโซนิคยังให้ API IndexOrGet()
อีกตัวหนึ่งเพื่อชดเชยการใช้งานพื้นฐาน รวมถึงตรวจสอบให้แน่ใจว่าคีย์ตรงกัน
Searcher
มีตัวเลือกสำหรับผู้ใช้เพื่อตอบสนองความต้องการที่แตกต่างกัน:
opts := ast. SearchOption { CopyReturn : true ... }
val , err := sonic . GetWithOptions ( JSON , opts , "key" )
ast.Node
ใช้การออกแบบ Lazy-Load
จึงไม่รองรับ Concurrently-Read ตามค่าเริ่มต้น หากต้องการอ่านพร้อมกันโปรดระบุแก้ไขเนื้อหา json โดย Set()/Unset()
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 จัดเตรียม API ขั้นสูงสำหรับการแยกวิเคราะห์ JSON ให้เป็นประเภทที่ไม่ได้มาตรฐานอย่างสมบูรณ์ (ทั้ง struct
ไม่ใช่ map[string]interface{}
) โดยไม่ต้องใช้การแสดงระดับกลางใดๆ ( ast.Node
หรือ interface{}
) ตัวอย่างเช่น คุณอาจมีประเภทต่อไปนี้ซึ่งเหมือนกับ 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 จัดเตรียม API ต่อไปนี้เพื่อส่งคืน การแวะผ่านการสั่งซื้อล่วงหน้าของ JSON AST ast.Visitor
เป็นอินเทอร์เฟซสไตล์ SAX ซึ่งใช้ในไลบรารี C++ JSON บางตัว คุณควรใช้ 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 สำหรับการใช้งานโดยละเอียด นอกจากนี้เรายังใช้ผู้เข้าชมสาธิตสำหรับ UserNode
ใน ast/visitor_test.go
สำหรับนักพัฒนาที่ต้องการใช้โซนิคเพื่อตอบสนองสถานการณ์ที่แตกต่างกัน เรามีการกำหนดค่าแบบรวมบางส่วนเป็น sonic.API
ConfigDefault
: การกำหนดค่าเริ่มต้นของโซนิค ( EscapeHTML=false
, SortKeys=false
...) เพื่อให้ทำงานด้วยเสียงได้อย่างรวดเร็วในขณะเดียวกันก็มั่นใจในความปลอดภัยConfigStd
: การกำหนดค่าที่เข้ากันได้กับมาตรฐาน ( EscapeHTML=true
, SortKeys=true
...)ConfigFastest
: การกำหนดค่าที่เร็วที่สุด ( NoQuoteTextMarshaler=true
) เพื่อให้ทำงานบนโซนิคได้เร็วที่สุด Sonic ไม่ รับประกันว่าจะรองรับทุกสภาพแวดล้อม เนื่องจากความยากลำบากในการพัฒนาโค้ดประสิทธิภาพสูง ในสภาพแวดล้อมที่ไม่รองรับเสียง การใช้งานจะถอยกลับไปเป็น encoding/json
ดังนั้นการกำหนดค่า beflow ทั้งหมดจะเท่ากับ ConfigStd
เนื่องจาก Sonic ใช้ golang-asm เป็นแอสเซมเบลอร์ JIT ซึ่งไม่เหมาะสำหรับการคอมไพล์รันไทม์ การเรียกใช้สคีมาขนาดใหญ่ครั้งแรกอาจทำให้เกิดการหมดเวลาคำขอหรือแม้แต่กระบวนการ OOM เพื่อความเสถียรที่ดีขึ้น เราขอแนะนำ ให้ใช้ Pretouch()
สำหรับสคีมาขนาดใหญ่หรือแอปพลิเคชันหน่วยความจำขนาดเล็ก ก่อน Marshal()/Unmarshal()
import (
"reflect"
"github.com/bytedance/sonic"
"github.com/bytedance/sonic/option"
)
func init () {
var v HugeStruct
// For most large types (nesting depth <= option.DefaultMaxIn