Что такое дедлок при работе с goroutine?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Дедлок (тупик) — это ситуация, когда две или более горутины блокируются, ожидая друг друга, и ни одна из них не может продолжить выполнение. Чаще всего возникает при работе с мьютексами или каналами.
Примеры дедлока:
-
Блокировка мьютексов в разном порядке:
// Пример дедлока с мьютексами var mu1 sync.Mutex var mu2 sync.Mutex func goroutine1() { mu1.Lock() // Захватывает mu1 time.Sleep(100 * time.Millisecond) // Ждет немного mu2.Lock() // Пытается захватить mu2 (занята goroutine2) fmt.Println("goroutine1 acquired mu2") mu2.Unlock() mu1.Unlock() } func goroutine2() { mu2.Lock() // Захватывает mu2 time.Sleep(100 * time.Millisecond) // Ждет немного mu1.Lock() // Пытается захватить mu1 (занята goroutine1) fmt.Println("goroutine2 acquired mu1") mu1.Unlock() mu2.Unlock() }Goroutine1 захватила
mu1и ждетmu2. Goroutine2 захватилаmu2и ждетmu1. Обе горутины заблокированы. -
Отправка в небуферизованный канал без получателя:
// Пример дедлока с каналом func main() { ch := make(chan int) //go func() { // Если не запустить горутину для чтения, будет дедлок // <-ch //}() ch <- 1 // Отправка в канал без активного получателя fmt.Println("Sent to channel") // Эта строка не будет достигнута }Отправка в небуферизованный канал блокируется до тех пор, пока другая горутина не начнет читать из него. Если получателя нет, происходит дедлок.
-
Чтение из канала без отправителя (после закрытия или пустой буферизованный):
// Пример дедлока при чтении из канала func main() { ch := make(chan int, 1) // Буферизованный канал на 1 элемент ch <- 1 // Отправили 1 close(ch) // Закрыли канал <-ch // Прочитали 1 <-ch // Пытаемся прочитать снова из закрытого и пустого канала - дедлок }Чтение из закрытого непустого канала завершится успешно. Чтение из закрытого и пустого канала или из открытого, но пустого небуферизованного канала без отправителя приведет к блокировке.
Golang-рантайм может обнаружить определенные типы дедлоков (например, когда все заблокированные горутины ожидают получения или отправки единственной горутины), и в таком случае программа аварийно завершится с сообщением "fatal error: all goroutines are asleep - deadlock!". Однако, не все дедлоки могут быть автоматически обнаружены.
Для предотвращения дедлоков важно:
- Соблюдать consistent порядок захвата мьютексов.
- Убедиться, что для каждой отправки в небуферизованный канал есть соответствующее чтение, и наоборот.
- При работе с каналами использовать
selectсdefaultветкой или тайм-аутами при необходимости. - Аккуратно управлять временем жизни горутин и закрытием каналов.