当前位置: 首页 > 面试题库 >

Concat字节数组

沈鸿光
2023-03-14
问题内容

有人可以指出以下更有效的版本吗

    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

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

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]


 类似资料:
  • 问题内容: 我试图理解一个到字符串,一个的字符串表示形式到转换…我将我的转换成一个要发送的字符串,然后我希望我的Web服务(用python编写)将数据直接回显给客户端。 当我从Java应用程序发送数据时… 字节发送.. 发送(这是Arrays.toString()的结果,它应该是我的字节数据的字符串表示形式,该数据将通过电线发送): 在python端,python服务器将字符串返回给调用方(我可以

  • concat 方法 连接两个或多个数组。 语法: arrayObject.concat( Array2, Array3, ...... ArrayN ); 参数说明: ArrayN - 必需。该参数可以是具体的值,也可以是数组对象。可以是任意多个。 返回值: 返回一个新的数组。该数组是通过把所有 arrayX 参数添加到 arrayObject 中生成的。如果要进行 concat()操作的参

  • concat 方法 连接两个或多个字符串。 语法: stringObject.concat( str, str, str, ... str ); 参数说明: str - 必需。将被连接为一个字符串的一个或多个字符串对象。 说明: concat() 方法将把它的所有参数转换成字符串,然后按顺序连接到字符串 stringObject 的尾部,并返回连接后的字符串。请注意,stringObject

  • 描述 (Description) Javascript数组concat()方法返回一个由此数组组成的新数组,该数组与两个或多个数组连接。 语法 (Syntax) concat()方法的语法如下 - array.concat(value1, value2, ..., valueN); valueN - 要连接到结果数组的数组和/或值。 返回值 (Return Value) 返回数组的长度。 例子

  • concat()方法返回一个由此数组组成的新数组,该数组与两个或多个数组连接。 语法 (Syntax) array.concat(value1, value2, ..., valueN); 参数 (Parameters) valueN - 要连接到结果数组的数组和/或值。 返回值 (Return Value) 返回一个新数组。 例子 (Example) var alpha = ["a", "b"

  • 此方法添加两个或多个字符串并返回一个新的单个字符串。 语法 (Syntax) string.concat(string2, string3[, ..., stringN]); 参数细节 (Argument Details) string2...stringN - 这些是要连接的字符串。 返回值 (Return Value) 返回单个连接字符串。 例子 (Example) var str1 =