Вопрос проверяет понимание проблемы гонки данных (data race) в многопоточных Go-программах и знание инструментов для её обнаружения.
Data race (гонка данных) — это ситуация в многопоточном программировании, когда несколько потоков (в Go — горутин) одновременно обращаются к одной и той же переменной, и хотя бы один из доступов является записью. При этом отсутствует синхронизация (например, с помощью мьютексов или каналов), что приводит к неопределённому поведению программы. Результат может зависеть от порядка выполнения потоков, который не гарантирован.
package main
import (
"fmt"
"sync"
)
var counter int
func main() {
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
counter++ // гонка: несколько горутин пишут в counter
}()
}
wg.Wait()
fmt.Println(counter) // результат непредсказуем
}В этом примере 1000 горутин одновременно увеличивают счётчик без синхронизации. Ожидаемый результат — 1000, но из-за гонки данных он может быть меньше.
Go предоставляет встроенный race detector. Для его активации нужно добавить флаг -race при компиляции, запуске или тестировании:
go run -race main.go
go test -race ./...Race detector анализирует все обращения к памяти и сообщает о потенциальных гонках. Он использует технологию отслеживания доступа (happens-before) и выводит подробный стек вызовов для каждого конфликтующего доступа.
Для устранения гонки данных нужно синхронизировать доступ к общим данным. В Go это делается с помощью:
sync.Mutex) — блокируют доступ к критической секции.sync/atomic) — для простых типов данных.Исправленный пример с мьютексом:
package main
import (
"fmt"
"sync"
)
var (
counter int
mu sync.Mutex
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
counter++
mu.Unlock()
}()
}
wg.Wait()
fmt.Println(counter) // всегда 1000
}Data race — серьёзная проблема в многопоточных программах, приводящая к недетерминированным ошибкам. В Go её легко обнаружить с помощью race detector, который следует использовать при разработке и тестировании. Для предотвращения гонок применяйте синхронизацию через мьютексы, каналы или атомарные операции. Это особенно важно в высоконагруженных системах, где параллелизм критичен.