👋 Канал OTUS в Telegram!
Посты от приглашенных гостей из IT-тусовки, полезные статьи, подборки вакансий от партнеров ➞
Подробнее

Курсы

Программирование
Архитектор программного обеспечения
-40%
Архитектура и шаблоны проектирования
-40%
Разработчик Java
-40%
Архитектор высоких нагрузок
-40%
Разработчик Node.js
-40%
Backend-разработчик на PHP
-30%
Symfony Framework
-30%
Разработчик на Spring Framework
-20%
Разработчик Golang
-25%
C# ASP.NET Core разработчик
-25%
iOS-разработчик. Базовый курс
-25%
Android-разработчик. Базовый курс VOIP инженер Базы данных Fullstack разработчик JavaScript Android-разработчик. Продвинутый курс Разработчик программных роботов (RPA) на базе UiPath и PIX Разработчик игр на Unity Vue.js разработчик Agile Project Manager в IT Супер - интенсив по паттернам проектирования Супер - интенсив по Kubernetes
Специализации Курсы в разработке Подготовительные курсы
+7 499 938-92-02

Программирование на языке Go: полезные советы. Часть 3

Go_deep_10.9_5020_12a219-5020-12a219.png

Предлагаем вашему вниманию последний блок полезных советов, которые будут интересны разработчикам Go. Предыдущие части находятся здесь и здесь. Материал является переводом статьи «Go Tips 101», который мы подготовили специально для вас.

1. Как определить фактическое (в зависимости от платформы) значение размера типа word на этапе компиляции?

Данный способ не является специфическим для языка Go:

const Is64bitArch = ^uint(0) >> 63 == 1
const Is32bitArch = ^uint(0) >> 63 == 0
const WordBits = 32 << (^uint(0) >> 63) // 64 or 32

2. Как объявить константы, равные максимальным значениям типов uint и int?

Это делается довольно просто:

const MaxUint = ^uint(0)
const MaxInt = int(^uint(0) >> 1)

3. Избегайте автоматического преобразования значений типов больших размеров в значения интерфейсных типов

При присвоении значения неинтерфейсного типа переменной интерфейсного типа создаваемая копия значения неинтерфейсного типа будет автоматически преобразована в значение интерфейсного типа. Затраты вычислительных ресурсов на подобное копирование зависят от размера неинтерфейсного типа. Чем больше размер, тем дороже обходится операция копирования. Поэтому настоятельно рекомендуется избегать автоматического преобразования значений типов больших размеров в значения интерфейсных типов.

В примере ниже вызов двух первых функций вывода осуществляется значительно медленнее, чем вызов двух последних.

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:])
}

Подробную информацию о размерах переменных разных типов и ресурсоемкости операций по их копированию см. в этой статье.

4. Оптимизируйте свой код с учётом механизма исключения необязательных проверок границ (bounds check elimination, BCE).

Для начала ознакомьтесь с подробной информацией о механизме BCE и поддержке BCE стандартным компилятором Go в этой статье.

Теперь давайте приведём дополнительный пример:

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)
    }
}

В примере выше функция NumSameBytes_2 является более эффективной, чем функция NumSameBytes_1. Результаты испытаний быстродействия:

BenchmarkNumSameBytes_1-4       10000000           669 ns/op
BenchmarkNumSameBytes_2-4       20000000           450 ns/op

Следует иметь в виду, что каждая новая версия стандартного компилятора Go (gc) содержит множество изменений, повышающих производительность. Оптимизация из приведенного выше примера не работает в Go SDK версий ниже 1.11. С другой стороны, вполне возможно, что в следующих более совершенных версиях gc отпадёт необходимость в использовании подобных приемов.

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться