Программирование на языке Go: полезные советы. Часть 3 | OTUS
🔥 BLACK FRIDAY!
Максимальная скидка -25% на всё. Успейте начать обучение по самой выгодной цене.
Выбрать курс

Курсы

Программирование
iOS Developer. Basic
-25%
Python Developer. Professional
-25%
Разработчик на Spring Framework
-25%
Golang Developer. Professional
-25%
Python Developer. Basic
-25%
iOS Developer. Professional
-25%
Highload Architect
-25%
JavaScript Developer. Basic
-25%
Kotlin Backend Developer
-25%
JavaScript Developer. Professional
-25%
Android Developer. Basic
-25%
Unity Game Developer. Basic
-25%
Разработчик C#
-25%
Программист С Web-разработчик на Python Алгоритмы и структуры данных Framework Laravel PostgreSQL Reverse-Engineering. Professional CI/CD Vue.js разработчик VOIP инженер Программист 1С Flutter Mobile Developer Супер - интенсив по Kubernetes Symfony Framework Advanced Fullstack JavaScript developer Супер-интенсив "Azure для разработчиков"
Инфраструктура
Мониторинг и логирование: Zabbix, Prometheus, ELK
-25%
DevOps практики и инструменты
-25%
Архитектор сетей
-25%
Инфраструктурная платформа на основе Kubernetes
-25%
Супер-интенсив «IaC Ansible»
-16%
Разработчик программных роботов (RPA) на базе UiPath и PIX
-25%
Супер-интенсив "SQL для анализа данных"
-16%
Базы данных Сетевой инженер AWS для разработчиков Cloud Solution Architecture Разработчик голосовых ассистентов и чат-ботов Внедрение и работа в DevSecOps Администратор Linux. Виртуализация и кластеризация Нереляционные базы данных Супер-практикум по использованию и настройке GIT IoT-разработчик Супер-интенсив «ELK»
Специализации Курсы в разработке Подготовительные курсы
+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 комментариев
Для комментирования необходимо авторизоваться
🎁 Максимальная скидка!
Черная пятница уже в OTUS! Скидка -25% на всё!