Čo je deadlock pri práci s goroutine?
sobes.tech AI
Odpoveď od AI
Deadlock (zaseknutie) je situácia, keď dve alebo viac gorutín blokujú jedna druhú, čakajúc na seba, a žiadna z nich nemôže pokračovať v vykonávaní. Najčastejšie k tomu dochádza pri práci s mutexmi alebo kanálmi.
Príklady deadlocku:
-
Zámky mutexov v rôznom poradí:
// Príklad deadlocku s mutexmi var mu1 sync.Mutex var mu2 sync.Mutex func goroutine1() { mu1.Lock() // Získa mu1 time.Sleep(100 * time.Millisecond) // Čaká trochu mu2.Lock() // Pokúša sa získať mu2 (ktorý drží goroutine2) fmt.Println("goroutine1 získal mu2") mu2.Unlock() mu1.Unlock() } func goroutine2() { mu2.Lock() // Získa mu2 time.Sleep(100 * time.Millisecond) // Čaká trochu mu1.Lock() // Pokúša sa získať mu1 (ktorý drží goroutine1) fmt.Println("goroutine2 získal mu1") mu1.Unlock() mu2.Unlock() }Goroutine1 získala
mu1a čaká namu2. Goroutine2 získalamu2a čaká namu1. Obidve gorutiny sú zablokované. -
Odoslanie do nebufferovaného kanála bez príjemcu:
// Príklad deadlocku s kanálom func main() { ch := make(chan int) //go func() { // Ak nespustíme gorutinu na čítanie, dôjde k deadlocku // <-ch //}() ch <- 1 // Odoslanie do kanála bez aktívneho príjemcu fmt.Println("Odoslané do kanála") // Táto riadok nebude dosiahnutý }Odoslanie do nebufferovaného kanála sa zablokuje, kým iná gorutina nezačne čítať z neho. Ak nie je žiadny príjemca, dôjde k deadlocku.
-
Čítanie z kanála bez odosielateľa (po zatvorení alebo prázdnom bufferovanom):
// Príklad deadlocku pri čítaní z kanála func main() { ch := make(chan int, 1) // Bufferovaný kanál na 1 prvok ch <- 1 // Odoslané 1 close(ch) // Zatvorili sme kanál <-ch // Prečítali 1 <-ch // Pokúšame sa čítať znova zo zatvoreného a prázdneho kanála - deadlock }Čítanie zo zatvoreného, neplneného kanála bude úspešné. Čítanie zo zatvoreného a prázdneho alebo z otvoreného, ale prázdneho nebufferovaného kanála bez odosielateľa spôsobí blokovanie.
Golang runtime môže detekovať určité typy deadlockov (napríklad, keď všetky zablokované gorutiny čakajú na prijatie alebo odoslanie od jednej gorutiny), a v takom prípade program neočakávane skončí s hlásením "fatal error: all goroutines are asleep - deadlock!". Avšak, nie všetky deadlocky môžu byť automaticky detekované.
Na prevenciu deadlockov je dôležité:
- Dodržiavať konzistentný poradie získavania mutexov.
- Zabezpečiť, že pre každé odoslanie do nebufferovaného kanála existuje zodpovedajúce čítanie, a naopak.
- Pri práci s kanálmi používať
selectsdefaultvetvou alebo časovými limitmi podľa potreby. - Dôsledne riadiť životnosť gorutín a zatváranie kanálov.