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.