有人可以指出以下更有效的版本吗
b:=make([]byte,0,sizeTotal) b=append(b,size...) b=append(b,contentType...) b=append(b,lenCallbackid...) b=append(b,lenTarget...) b=append(b,lenAction...) b=append(b,lenContent...) b=append(b,callbackid...) b=append(b,target...) b=append(b,action...) b=append(b,content...)
每个变量都是一个字节片,大小不一 sizeTotal
sizeTotal
Update:
Update
码:
type Message struct { size uint32 contentType uint8 callbackId string target string action string content string } var res []byte var b []byte = make([]byte,0,4096) func (m *Message)ToByte()[]byte{ callbackIdIntLen:=len(m.callbackId) targetIntLen := len(m.target) actionIntLen := len(m.action) contentIntLen := len(m.content) lenCallbackid:=make([]byte,4) binary.LittleEndian.PutUint32(lenCallbackid, uint32(callbackIdIntLen)) callbackid := []byte(m.callbackId) lenTarget := make([]byte,4) binary.LittleEndian.PutUint32(lenTarget, uint32(targetIntLen)) target:=[]byte(m.target) lenAction := make([]byte,4) binary.LittleEndian.PutUint32(lenAction, uint32(actionIntLen)) action := []byte(m.action) lenContent:= make([]byte,4) binary.LittleEndian.PutUint32(lenContent, uint32(contentIntLen)) content := []byte(m.content) sizeTotal:= 21+callbackIdIntLen+targetIntLen+actionIntLen+contentIntLen size := make([]byte,4) binary.LittleEndian.PutUint32(size, uint32(sizeTotal)) b=b[:0] b=append(b,size...) b=append(b,byte(m.contentType)) b=append(b,lenCallbackid...) b=append(b,lenTarget...) b=append(b,lenAction...) b=append(b,lenContent...) b=append(b,callbackid...) b=append(b,target...) b=append(b,action...) b=append(b,content...) res = b return b } func FromByte(bytes []byte)(*Message){ size :=binary.LittleEndian.Uint32(bytes[0:4]) contentType :=bytes[4:5][0] lenCallbackid:=binary.LittleEndian.Uint32(bytes[5:9]) lenTarget :=binary.LittleEndian.Uint32(bytes[9:13]) lenAction :=binary.LittleEndian.Uint32(bytes[13:17]) lenContent :=binary.LittleEndian.Uint32(bytes[17:21]) callbackid := string(bytes[21:21+lenCallbackid]) target:= string(bytes[21+lenCallbackid:21+lenCallbackid+lenTarget]) action:= string(bytes[21+lenCallbackid+lenTarget:21+lenCallbackid+lenTarget+lenAction]) content:=string(bytes[size-lenContent:size]) return &Message{size,contentType,callbackid,target,action,content} }
Benchs:
Benchs
func BenchmarkMessageToByte(b *testing.B) { m:=NewMessage(uint8(3),"agsdggsdasagdsdgsgddggds","sometarSFAFFget","somFSAFSAFFSeaction","somfasfsasfafsejsonzhit") for n := 0; n < b.N; n++ { m.ToByte() } } func BenchmarkMessageFromByte(b *testing.B) { m:=NewMessage(uint8(1),"sagdsgaasdg","soSASFASFASAFSFASFAGmetarget","adsgdgsagdssgdsgd","agsdsdgsagdsdgasdg").ToByte() for n := 0; n < b.N; n++ { FromByte(m) } } func BenchmarkStringToByte(b *testing.B) { for n := 0; n < b.N; n++ { _ = []byte("abcdefghijklmnoqrstuvwxyz") } } func BenchmarkStringFromByte(b *testing.B) { s:=[]byte("abcdefghijklmnoqrstuvwxyz") for n := 0; n < b.N; n++ { _ = string(s) } } func BenchmarkUintToByte(b *testing.B) { for n := 0; n < b.N; n++ { i:=make([]byte,4) binary.LittleEndian.PutUint32(i, uint32(99)) } } func BenchmarkUintFromByte(b *testing.B) { i:=make([]byte,4) binary.LittleEndian.PutUint32(i, uint32(99)) for n := 0; n < b.N; n++ { binary.LittleEndian.Uint32(i) } }
基准测试结果:
BenchmarkMessageToByte 10000000 280 ns/op BenchmarkMessageFromByte 10000000 293 ns/op BenchmarkStringToByte 50000000 55.1 ns/op BenchmarkStringFromByte 50000000 49.7 ns/op BenchmarkUintToByte 1000000000 2.14 ns/op BenchmarkUintFromByte 2000000000 1.71 ns/op
如果已经分配了内存,则x = append(x,a …)的序列在Go中非常有效。
在您的示例中,初始分配(制造)的成本可能比附加序列的成本高。这取决于字段的大小。考虑以下基准:
package main import ( "testing" ) const sizeTotal = 25 var res []byte // To enforce heap allocation func BenchmarkWithAlloc(b *testing.B) { a := []byte("abcde") for i := 0; i < b.N; i++ { x := make([]byte, 0, sizeTotal) x = append(x, a...) x = append(x, a...) x = append(x, a...) x = append(x, a...) x = append(x, a...) res = x // Make sure x escapes, and is therefore heap allocated } } func BenchmarkWithoutAlloc(b *testing.B) { a := []byte("abcde") x := make([]byte, 0, sizeTotal) for i := 0; i < b.N; i++ { x = x[:0] x = append(x, a...) x = append(x, a...) x = append(x, a...) x = append(x, a...) x = append(x, a...) res = x } }
在我的盒子上,结果是:
testing: warning: no tests to run PASS BenchmarkWithAlloc 10000000 116 ns/op 32 B/op 1 allocs/op BenchmarkWithoutAlloc 50000000 24.0 ns/op 0 B/op 0 allocs/op
系统地重新分配缓冲区(甚至是很小的缓冲区)会使此基准测试速度至少慢5倍。
因此,您最好希望对此代码进行优化,以确保您不会为所构建的每个数据包重新分配缓冲区。相反,您应该保留缓冲区,并在每次编组操作中重用它。
您可以重置切片,同时使用以下语句保留其基础缓冲区的分配:
x = x[:0]