0 added
0 removed
Original
2026-01-01
Modified
2026-03-10
1
<p>Теги: go, golang, программирование на go, разработка на go, bce</p>
1
<p>Теги: go, golang, программирование на go, разработка на go, bce</p>
2
<p>Предлагаем вашему вниманию последний блок полезных советов, которые будут интересны разработчикам Go. Предыдущие части находятся<a>здесь</a>и<a>здесь</a>. Материал является переводом статьи "<a>Go Tips 101</a>", который мы подготовили специально для вас.</p>
2
<p>Предлагаем вашему вниманию последний блок полезных советов, которые будут интересны разработчикам Go. Предыдущие части находятся<a>здесь</a>и<a>здесь</a>. Материал является переводом статьи "<a>Go Tips 101</a>", который мы подготовили специально для вас.</p>
3
<h2>1. Как определить фактическое (в зависимости от платформы) значение размера типа word на этапе компиляции?</h2>
3
<h2>1. Как определить фактическое (в зависимости от платформы) значение размера типа word на этапе компиляции?</h2>
4
<p>Данный способ не является специфическим для языка Go:</p>
4
<p>Данный способ не является специфическим для языка Go:</p>
5
const Is64bitArch = ^uint(0) >> 63 == 1 const Is32bitArch = ^uint(0) >> 63 == 0 const WordBits = 32 << (^uint(0) >> 63) // 64 or 32<h2>2. Как объявить константы, равные максимальным значениям типов uint и int?</h2>
5
const Is64bitArch = ^uint(0) >> 63 == 1 const Is32bitArch = ^uint(0) >> 63 == 0 const WordBits = 32 << (^uint(0) >> 63) // 64 or 32<h2>2. Как объявить константы, равные максимальным значениям типов uint и int?</h2>
6
<p>Это делается довольно просто:</p>
6
<p>Это делается довольно просто:</p>
7
const MaxUint = ^uint(0) const MaxInt = int(^uint(0) >> 1)<h2>3. Избегайте автоматического преобразования значений типов больших размеров в значения интерфейсных типов</h2>
7
const MaxUint = ^uint(0) const MaxInt = int(^uint(0) >> 1)<h2>3. Избегайте автоматического преобразования значений типов больших размеров в значения интерфейсных типов</h2>
8
<p>При присвоении значения неинтерфейсного типа переменной интерфейсного типа создаваемая копия значения неинтерфейсного типа будет автоматически преобразована в значение интерфейсного типа. Затраты вычислительных ресурсов на подобное копирование зависят от размера неинтерфейсного типа. Чем больше размер, тем дороже обходится операция копирования. Поэтому настоятельно рекомендуется<strong>избегать автоматического преобразования</strong>значений типов больших размеров в значения интерфейсных типов.</p>
8
<p>При присвоении значения неинтерфейсного типа переменной интерфейсного типа создаваемая копия значения неинтерфейсного типа будет автоматически преобразована в значение интерфейсного типа. Затраты вычислительных ресурсов на подобное копирование зависят от размера неинтерфейсного типа. Чем больше размер, тем дороже обходится операция копирования. Поэтому настоятельно рекомендуется<strong>избегать автоматического преобразования</strong>значений типов больших размеров в значения интерфейсных типов.</p>
9
<p>В примере ниже вызов двух первых функций вывода осуществляется значительно медленнее, чем вызов двух последних.</p>
9
<p>В примере ниже вызов двух первых функций вывода осуществляется значительно медленнее, чем вызов двух последних.</p>
10
package main import "fmt" func main() { var a [1000]int // Ресурсоемкий код: fmt.Println(a) // значение a копируется fmt.Printf("Type of a: %T\n", a) // значение a копируется // The cost of the two lines is low. fmt.Printf("%v\n", a[:]) fmt.Println("Type of a:", fmt.Sprintf("%T", &a)[1:]) }<p>Подробную информацию о размерах переменных разных типов и ресурсоемкости операций по их копированию см. в<a>этой статье</a>.</p>
10
package main import "fmt" func main() { var a [1000]int // Ресурсоемкий код: fmt.Println(a) // значение a копируется fmt.Printf("Type of a: %T\n", a) // значение a копируется // The cost of the two lines is low. fmt.Printf("%v\n", a[:]) fmt.Println("Type of a:", fmt.Sprintf("%T", &a)[1:]) }<p>Подробную информацию о размерах переменных разных типов и ресурсоемкости операций по их копированию см. в<a>этой статье</a>.</p>
11
<h2>4. Оптимизируйте свой код с учётом механизма исключения необязательных проверок границ (bounds check elimination, BCE).</h2>
11
<h2>4. Оптимизируйте свой код с учётом механизма исключения необязательных проверок границ (bounds check elimination, BCE).</h2>
12
<p>Для начала ознакомьтесь с подробной информацией о механизме BCE и поддержке BCE стандартным компилятором Go в<a>этой статье</a>.</p>
12
<p>Для начала ознакомьтесь с подробной информацией о механизме BCE и поддержке BCE стандартным компилятором Go в<a>этой статье</a>.</p>
13
<p>Теперь давайте приведём дополнительный пример:</p>
13
<p>Теперь давайте приведём дополнительный пример:</p>
14
package main import ( "strings" "testing" ) func NumSameBytes_1(x, y string) int { if len(x) > len(y) { x, y = y, x } for i := 0; i < len(x); i++ { if x[i] != y[i] { return i } } return len(x) } func NumSameBytes_2(x, y string) int { if len(x) > len(y) { x, y = y, x } if len(x) <= len(y) { // более длинный, но более эффективный код for i := 0; i < len(x); i++ { if x[i] != y[i] { // проверка границ не выполняется return i } } } return len(x) } var x = strings.Repeat("hello", 100) + " world!" var y = strings.Repeat("hello", 99) + " world!" func BenchmarkNumSameBytes_1(b *testing.B) { for i := 0; i < b.N; i++ { _ = NumSameBytes_1(x, y) } } func BenchmarkNumSameBytes_2(b *testing.B) { for i := 0; i < b.N; i++ { _ = NumSameBytes_2(x, y) } }<p>В примере выше функция NumSameBytes_2 является более эффективной, чем функция NumSameBytes_1. Результаты испытаний быстродействия:</p>
14
package main import ( "strings" "testing" ) func NumSameBytes_1(x, y string) int { if len(x) > len(y) { x, y = y, x } for i := 0; i < len(x); i++ { if x[i] != y[i] { return i } } return len(x) } func NumSameBytes_2(x, y string) int { if len(x) > len(y) { x, y = y, x } if len(x) <= len(y) { // более длинный, но более эффективный код for i := 0; i < len(x); i++ { if x[i] != y[i] { // проверка границ не выполняется return i } } } return len(x) } var x = strings.Repeat("hello", 100) + " world!" var y = strings.Repeat("hello", 99) + " world!" func BenchmarkNumSameBytes_1(b *testing.B) { for i := 0; i < b.N; i++ { _ = NumSameBytes_1(x, y) } } func BenchmarkNumSameBytes_2(b *testing.B) { for i := 0; i < b.N; i++ { _ = NumSameBytes_2(x, y) } }<p>В примере выше функция NumSameBytes_2 является более эффективной, чем функция NumSameBytes_1. Результаты испытаний быстродействия:</p>
15
BenchmarkNumSameBytes_1-4 10000000 669 ns/op BenchmarkNumSameBytes_2-4 20000000 450 ns/op<p>Следует иметь в виду, что каждая новая версия стандартного компилятора Go (gc) содержит множество изменений, повышающих производительность. Оптимизация из приведенного выше примера не работает в Go SDK версий ниже 1.11. С другой стороны, вполне возможно, что в следующих более совершенных версиях gc отпадёт необходимость в использовании подобных приемов.</p>
15
BenchmarkNumSameBytes_1-4 10000000 669 ns/op BenchmarkNumSameBytes_2-4 20000000 450 ns/op<p>Следует иметь в виду, что каждая новая версия стандартного компилятора Go (gc) содержит множество изменений, повышающих производительность. Оптимизация из приведенного выше примера не работает в Go SDK версий ниже 1.11. С другой стороны, вполне возможно, что в следующих более совершенных версиях gc отпадёт необходимость в использовании подобных приемов.</p>
16
16