Какво е deadlock при работа с goroutine?
sobes.tech AI
Отговор от AI
Deadlock (задръстване) е ситуация, когато две или повече горутини блокират една друга, очаквайки една друга, и никоя от тях не може да продължи изпълнението. Най-често се случва при работа с мютекси или канали.
Примери за deadlock:
-
Блокиране на мютекси в различен ред:
// Пример за deadlock с мютекси 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 взема mu2") mu2.Unlock() mu1.Unlock() } func goroutine2() { mu2.Lock() // Взема mu2 time.Sleep(100 * time.Millisecond) // Чака малко mu1.Lock() // Опитва се да вземе mu1 (който държи goroutine1) fmt.Println("goroutine2 взема mu1") mu1.Unlock() mu2.Unlock() }Goroutine1 взема
mu1и чакаmu2. Goroutine2 вземаmu2и чакаmu1. И двете горутини са блокирани. -
Изпращане към небуфериран канал без получател:
// Пример за deadlock с канал func main() { ch := make(chan int) //go func() { // Ако не стартираме горутина за четене, ще има deadlock // <-ch //}() ch <- 1 // Изпращане към канала без активен получател fmt.Println("Изпратено към канала") // Тази линия няма да бъде достигната }Изпращането към небуфериран канал блокира, докато друга горутина не започне да чете от него. Ако няма получател, възниква deadlock.
-
Четене от канал без изпращач (след затваряне или празен буфериран):
// Пример за deadlock при четене от канал func main() { ch := make(chan int, 1) // Буфериран канал с 1 елемент ch <- 1 // Изпратихме 1 close(ch) // Затворихме канала <-ch // Прочетохме 1 <-ch // Опитваме се да прочетем отново от затворен и празен канал - deadlock }Четенето от затворен, непълен канал ще завърши успешно. Четенето от затворен и празен или от отворен, но празен небуфериран канал без изпращач ще доведе до блокиране.
Golang runtime може да открие определени видове deadlock (например, когато всички блокирани горутини очакват получаване или изпращане на единствена горутина), и в такъв случай програмата ще се прекъсне с съобщение "fatal error: all goroutines are asleep - deadlock!". Въпреки това, не всички deadlock-и могат да бъдат автоматично открити.
За предотвратяване на deadlock-и е важно:
- Да се спазва последователен ред при взимане на мютекси.
- Да се гарантира, че за всяко изпращане към небуфериран канал има съответно четене, и обратното.
- При работа с канали да се използва
selectсdefaultклон или тайм-аутове при необходимост. - Внимателно да се управлява жизненият цикъл на горутините и затварянето на каналите.