Ответ
Неправильная синхронизация в конкурентных программах на Go приводит к трудноуловимым ошибкам и проблемам с производительностью. Основные последствия:
-
Состояние гонки (Race Condition). Возникает, когда несколько горутин одновременно обращаются к одной и той же области памяти, и хотя бы одна из них выполняет запись. Результат операции становится непредсказуемым и зависит от порядка выполнения горутин, что приводит к повреждению данных.
var counter int // Запускаем две горутины, инкрементирующие счетчик go func() { counter++ }() go func() { counter++ }() // Финальное значение counter может быть 1 или 2
Диагностика:
go run -race
илиgo test -race
. -
Взаимоблокировка (Deadlock). Ситуация, когда две или более горутины бесконечно ожидают друг друга, блокируя ресурсы, необходимые другим. Программа полностью "зависает".
var muA, muB sync.Mutex // Горутина 1: A -> B go func() { muA.Lock() time.Sleep(time.Millisecond) muB.Lock() // Ждет, пока Горутина 2 освободит muB // ... muA.Unlock() muB.Unlock() }() // Горутина 2: B -> A go func() { muB.Lock() time.Sleep(time.Millisecond) muA.Lock() // Ждет, пока Горутина 1 освободит muA // ... muB.Unlock() muA.Unlock() }() // Результат - deadlock
-
Живая блокировка (Livelock). Горутины постоянно изменяют свое состояние в ответ на действия друг друга, но не выполняют полезной работы. В отличие от deadlock, они активны, но "топчутся на месте".
-
Голодание (Starvation). Одна или несколько горутин не могут получить доступ к ресурсу, потому что он постоянно занят другими, более "жадными" или высокоприоритетными горутинами.
-
Утечки горутин. Как следствие неправильной синхронизации (например, ожидание данных из канала, в который никто не пишет), горутины могут остаться заблокированными навсегда, потребляя память.