Как мне сделать БЫСТРОЕ преобразование массива int в массив байтов? - PullRequest
1 голос
/ 19 апреля 2019

У меня есть процесс, который должен упаковать большой массив int16 s в protobuf каждые несколько миллисекунд.Понимание его протобуфской стороны не критично, так как все, что мне действительно нужно, - это способ конвертировать кучу int16 с (160-16k из них) в []byte.Это критичная для процессора операция, поэтому я не хочу делать что-то вроде этого:

for _, sample := range listOfIntegers {
  protobufObject.ByteStream = append(protobufObject.Bytestream, byte(sample>>8))
  protobufObject.ByteStream = append(protobufObject.Bytestream, byte(sample&0xff))
}

(Если вам интересно, это protobuf)

message ProtobufObject {
  bytes byte_stream = 1;
  ...               = 2;
  etc.
}

ТамДолжен быть более быстрый способ предоставления этого списка целых чисел как блока памяти для protobuf.Я возился с библиотекой cgo, чтобы получить доступ к memcpy, но подозреваю, что разрушаю основную структуру данных go, потому что у меня возникают сбои в совершенно не связанных частях кода.

1 Ответ

1 голос
/ 19 апреля 2019

Более быстрый вариант кода выше:

protobufObject.ByteStream := make([]byte, len(listOfIntegers) * 2)
for i, n := range listOfIntegers {
  j := i * 2
  protobufObject.ByteStream[j+1] = byte(n)
  protobufObject.ByteStream[j] = byte(n>>8)
}

Вы можете избежать копирования данных при работе на архитектуре с прямым порядком байтов.

Используйте пакет unsafe , чтобы скопировать заголовок []int16 в заголовок []byte. Снова используйте небезопасный пакет, чтобы получить указатель на заголовок []byte и настроить длину и емкость для преобразования.

b = *(*[]byte)(unsafe.Pointer(&listOfIntegers))
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&b))
hdr.Len *= 2
hdr.Cap *= 2
protobufObject.ByteStream = b
...