Ответ
При написании конкурентного кода в Go можно столкнуться с несколькими классическими проблемами. Вот основные из них:
1. Гонка данных (Data Race)
- Проблема: Возникает, когда две или более горутины одновременно обращаются к одной и той же области памяти, и хотя бы одна из них выполняет запись. Результат операции становится непредсказуемым.
- Пример:
var counter int // Две горутины инкрементируют счетчик без синхронизации go func() { counter++ }() go func() { counter++ }() // Финальное значение counter может быть 1 или 2
- Решение: Использовать примитивы синхронизации для защиты общих данных:
sync.Mutex
илиsync.RWMutex
для эксклюзивного доступа.- Каналы (channels) для безопасной передачи данных между горутинами.
- Атомарные операции из пакета
sync/atomic
.
- Диагностика: Использовать встроенный детектор гонок:
go run -race main.go
.
2. Взаимная блокировка (Deadlock)
- Проблема: Ситуация, когда две или более горутины бесконечно ожидают освобождения ресурсов, захваченных друг другом. Программа "зависает".
- Пример (неправильный порядок захвата мьютексов):
var mu1, mu2 sync.Mutex go func() { // Горутина 1 mu1.Lock() time.Sleep(10 * time.Millisecond) mu2.Lock() // Ждет, пока Горутина 2 освободит mu2 // ... mu1.Unlock() mu2.Unlock() }() go func() { // Горутина 2 mu2.Lock() time.Sleep(10 * time.Millisecond) mu1.Lock() // Ждет, пока Горутина 1 освободит mu1 // ... mu2.Unlock() mu1.Unlock() }()
- Решение: Вводить строгий порядок захвата блокировок. Все горутины должны захватывать мьютексы в одной и той же последовательности (например, всегда сначала
mu1
, потомmu2
).
3. Голодание (Starvation)
- Проблема: Одна или несколько горутин не могут получить доступ к необходимому ресурсу и не могут продолжить свою работу, в то время как другие горутины постоянно этот ресурс используют.
- Пример: Может возникнуть при неправильном использовании мьютексов, когда одна "жадная" горутина постоянно захватывает и освобождает мьютекс в цикле, не давая другим горутинам шанса его захватить.
- Решение: Справедливое распределение доступа к ресурсам. В Go
sync.Mutex
не гарантирует справедливость, но на практике голодание встречается редко. Использование каналов для управления доступом может помочь спроектировать более справедливую систему.