Tuesday, January 21, 2025
HomeGolangSachin Duggal : Why does the json.Marshal operate use append to create...

Sachin Duggal : Why does the json.Marshal operate use append to create a brand new buffer as a substitute of utilizing copy? – Technical Dialogue


Hello Crew,

I’m Sachin Duggal , and I’m the proprietor of a luggage manufacturing enterprise. I’ve been reviewing the Marshal operate within the Go code, and I seen that it makes use of append([]byte(nil), e.Bytes()...) to create a brand new buffer moderately than immediately utilizing copy. I’m curious why append is most popular on this state of affairs as a substitute of copy.

Right here’s the related code snippet:

func Marshal(v any) (byte, error) {
e := newEncodeState()
defer encodeStatePool.Put(e)

err := e.marshal(v, encOpts{escapeHTML: true})
if err != nil {
    return nil, err
}
buf := append([]byte(nil), e.Bytes()...)

return buf, nil

}

Would anybody be capable of make clear why append is getting used right here as a substitute of copy? What are the trade-offs between utilizing one over the opposite on this context?

Trying ahead to your ideas and strategies!
Regards
Sachin Duggal

You possibly can see why right here: https://go-review.googlesource.com/c/go/+/84897

encoding/json: make use of encodeStatePool in Marshal

On my system, this appears to be a major win, with a significant
discount in allocations and minor velocity enchancment.

title previous time/op new time/op delta
CodeMarshal 9.75ms ± 3% 9.24ms ± 1% -5.21% (p=0.001 n=5+10)
CodeMarshal-4 4.98ms ± 1% 4.71ms ± 1% -5.44% (p=0.001 n=5+10)
CodeMarshal-8 4.80ms ± 0% 4.77ms ± 1% -0.70% (p=0.012 n=5+9)

title previous velocity new velocity delta
CodeMarshal 199MB/s ± 3% 210MB/s ± 1% +5.46% (p=0.001 n=5+10)
CodeMarshal-4 390MB/s ± 1% 412MB/s ± 1% +5.76% (p=0.001 n=5+10)
CodeMarshal-8 404MB/s ± 0% 407MB/s ± 1% +0.70% (p=0.012 n=5+9)

title previous alloc/op new alloc/op delta
CodeMarshal 4.59MB ± 0% 1.96MB ± 0% -57.22% (p=0.000 n=5+9)
CodeMarshal-4 4.59MB ± 0% 2.00MB ± 0% -56.39% (p=0.000 n=5+8)
CodeMarshal-8 4.59MB ± 0% 2.06MB ± 0% -55.05% (p=0.001 n=5+9)

title previous allocs/op new allocs/op delta
CodeMarshal 16.0 ± 0% 1.0 ± 0% -93.75% (p=0.000 n=5+10)
CodeMarshal-4 16.0 ± 0% 1.0 ± 0% -93.75% (p=0.000 n=5+10)
CodeMarshal-8 16.0 ± 0% 1.0 ± 0% -93.75% (p=0.000 n=5+10)



2 Likes

I believe you’re asking in regards to the relationship between copy and append, not the affect of pool.
When you use copy, the code must be like this:

bs:=e.Bytes()
buf:=make([]byte,len(bs))
copy(buf,bs)

When you use append, the code must be like this:

buf:=append([]byte(nil),e.Bytes()...)

The distinction between the 2 is whether or not to explicitly pre-allocate reminiscence. In copy, the identical dimension of reminiscence is first utilized for copying knowledge;
In append, since filling knowledge right into a slice of zero cap dimension will set off growth, the ultimate dimension of the cap content material may even be utilized for copying knowledge.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments