Механика языка и гонки данных
См. также: Асинхронность и горутины · Синтаксические конструкции · Обработка ошибок.
Порядок инициализации
При запуске программы Go выполняет:
- Инициализацию пакетов в порядке импорта (зависимости раньше зависимых).
- В каждом пакете — присваивания переменным уровня пакета, затем все функции
init()(их может быть несколько в одном файле). - Функцию
mainв пакетеmain.
func init() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
}
init нельзя вызвать вручную. Используют для регистрации драйверов БД (import _ "github.com/lib/pq"), глобальных настроек, проверок окружения. Избегайте тяжёлой логики и сетевых вызовов в init — усложняет тесты и скрывает зависимости.
Пустой идентификатор _
Игнорирует значение:
_ = riskyCall() // явно «результат не нужен»
for _, item := range list { }
f, _ := os.Open("x") // ошибку намеренно не обрабатывают — только если обосновано
В импорте _ означает импорт только ради побочного эффекта (вызов init пакета):
import _ "net/http/pprof"
import _ "image/png"
Имя пакета при этом не попадает в область видимости — нельзя писать pprof.StartCPUProfile без обычного импорта.
Направленные каналы
Тип канала может ограничивать операции:
func producer(out chan<- int) { out <- 42 }
func consumer(in <-chan int) { v := <-in }
chan<- T — только отправка; <-chan T — только приём. chan T — оба направления. Это контракт API: функция не сможет случайно читать из канала, в который только пишет.
Закрытие — только на стороне отправителя; получатель проверяет:
v, ok := <-ch
if !ok {
// канал закрыт
}
Подробнее о паттернах — асинхронность.
Типичные гонки данных
Гонка — два потока обращаются к одной памяти, хотя бы один пишет, без синхронизации.
Замыкание в цикле
for i := 0; i < 3; i++ {
go func() {
fmt.Println(i) // часто три раза «3»
}()
}
Исправление — передать копию:
for i := 0; i < 3; i++ {
i := i
go func() { fmt.Println(i) }()
}
Общая map без mutex
Карты не потокобезопасны. Варианты: sync.Mutex + map, sync.Map для read-heavy кэшей, или одна горутина-владелец map и канал команд.
Срез из нескольких горутин
append может гонять за внутренний массив. Либо mutex, либо каждая горутина пишет в свой кусок, либо агрегация через канал.
sync-примитивы (кратко)
| Тип | Назначение |
|---|---|
sync.Mutex / RWMutex | Защита общих структур |
sync.WaitGroup | Дождаться N горутин |
sync.Once | Однократная инициализация |
atomic | Счётчики, флаги без mutex |
Предпочитайте передачу данных каналами, когда владение однозначно; mutex — когда общее состояние сложное.
Детектор гонок
Включение при тестах и локальном запуске:
go test -race ./...
go run -race .
Runtime отслеживает небезопасный доступ и печатает стек. Замедляет выполнение — в production не включают, в CI — да.
Статический go vet дополняет (например, копирование lock в структуре). Вместе с -race это базовый минимум для конкурентного кода.
Чек-лист перед code review
- Есть ли
goвнутриforс переменными цикла? - Разделяют ли горутины map/slice без синхронизации?
- Закрывает ли канал только отправитель?
- Запускали ли
go test -raceдля затронутых пакетов?
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). Основы языка Go - философия простоты, модель компиляции и идиоматичный подход к системной разработке. Go — это статически типизированный язык программирования общего назначения, разработанный компанией Google для создания эффективных, масштабируемых и надежных систем. Набор советов, правил, принципов и обычаев в разработке на этом языке. История Go - инженерные цели языка, философия простоты и эволюция инструментов экосистемы. Экосистема приложений на Go - встроенные инструменты, workflow разработки и практики сопровождения проектов. Кавычки, rune и string, точка, запятая, автоматическая вставка точки с запятой, скобки, подчёркивания и типичные ошибки новичков в Go. Предопределённые идентификаторы не являются ключевыми словами, но имеют специальное значение в языке. Их можно переопределить в локальной области видимости, но делать это не рекомендуется. Набор функций, которые включены в стандартную библиотеку языка. Особенности Go - интерфейсы, композиция, модель ошибок и практики написания поддерживаемого кода. Go вводит конкурентность через встроенные синтаксические конструкции и правила выполнения. Ниже рассматриваются основные направления практического применения Go, объяснённые через призму его технических характеристик и требований реальных инфраструктур. Типизация, набор правил определения типа данных значений языка.Основы языка Go
Что требуется знать перед началом изучения языка программирования Go
Рекомендации по разработке на Go
История языка Go
Экосистема приложений на Go
Синтаксис и пунктуация в Go
Ключевые слова языка Go
Встроенные функции и пакеты Go
Особенности языка Go
Синтаксические конструкции Go
Области применения Go
Типы данных и объявление переменных в Go