Оптимизация заполнения структуры данных/выравнивания слов в golang

Подобно тому, что я узнал из C++, я считаю, что именно заполнение вызывает разницу в размере экземпляров обеих структур.

type Foo struct {
    w byte //1 byte
    x byte //1 byte
    y uint64 //8 bytes
}
type Bar struct {
    x byte //1 byte
    y uint64 //8 bytes
    w byte// 1 byte
}
func main() {
    fmt.Println(runtime.GOARCH)
    newFoo := new(Foo)
    fmt.Println(unsafe.Sizeof(*newFoo))
    newBar := new(Bar)
    fmt.Println(unsafe.Sizeof(*newBar))
}

Выход:

amd64
16
24
  • Есть ли эмпирическое правило, которому нужно следовать при определении членов структуры? (например, в порядке возрастания/убывания размера типов)
  • Есть ли оптимизация времени компиляции, которую мы можем пройти, которая может автоматически позаботиться об этом?
  • Или мне вообще не стоит об этом беспокоиться?

person nohup    schedule 21.08.2016    source источник
comment
Я сделал пример, который может дать некоторую информацию play.golang.org/p/dNWspo2Dxv   -  person jpgerek    schedule 12.11.2016


Ответы (3)


В настоящее время нет оптимизации времени компиляции; значения дополняются до 8 байтов на x64.

Вы можете вручную расположить структуры для оптимального использования пространства; как правило, переходя от более крупных типов к более мелким; Например, 8 последовательных байтовых полей будут использовать только 8 байтов, но один байт будет дополнен до 8-байтового выравнивания, учтите следующее: https://play.golang.org/p/0qsgpuAHHp

package main

import (
    "fmt"
    "unsafe"
)

type Compact struct {
    a, b                   uint64
    c, d, e, f, g, h, i, j byte
}

// Larger memory footprint than "Compact" - but less fields!
type Inefficient struct {
    a uint64
    b byte
    c uint64
    d byte
}

func main() {
    newCompact := new(Compact)
    fmt.Println(unsafe.Sizeof(*newCompact))
    newInefficient := new(Inefficient)
    fmt.Println(unsafe.Sizeof(*newInefficient))
}

Если вы примете это во внимание; вы можете оптимизировать объем памяти ваших структур.

person Martin Gallagher    schedule 21.08.2016
comment
Я также хотел бы добавить, что вы можете визуализировать свою структуру с помощью таких инструментов, как structlayout и < href="https://github.com/opennota/check" rel="nofollow noreferrer">aligncheck, который поможет вам оптимизировать расположение структур. - person Chewxy; 26.09.2016

Или мне вообще не стоит об этом беспокоиться?

Да, следует.
Это также называется механическая симпатия (см. этот эпизод подкаста Go Time), так что это также зависит от аппаратной архитектуры, для которой вы компилируете .

См. в качестве иллюстрации:

Значения в срезах Go выровнены по 16 байтам. Они не выровнены по 32 байтам.
Указатели Go выровнены по байтам.

person VonC    schedule 21.08.2016
comment
Я также пытался исправить ссылку 2014 года, но сайт kernel-panic.runkite.com, похоже, исчез. - person Arnaud P; 06.05.2021
comment
@ArnaudP Спасибо за ваше редактирование. Я также восстановил ссылку kernel-panic.runkite.com. - person VonC; 06.05.2021

Это зависит от типа приложения, которое вы разрабатываете, и от использования этих структур. Если приложение должно соответствовать некоторым критериям памяти/производительности, вам определенно следует позаботиться о выравнивании памяти и заполнении, но не только - есть хорошая статья https://www.usenix.org/legacy/publications/library/proceedings/als00/2000papers/papers/full_papers/sears/sears_html/index.html, в котором освещается тема оптимального использования кэшей ЦП и корреляция между макетами структур и производительностью. Он выделяет выравнивание строки кэша, ложное совместное использование и т. д.

Также есть хороший инструмент golang https://github.com/1pkg/gopium, который помогает автоматизировать эти оптимизации, проверьте это!

person John Brown    schedule 13.06.2020