Kas ir deadlock, strādājot ar goroutine?
sobes.tech AI
Atbilde no AI
Deadlock (saslēgšanās) ir situācija, kad divas vai vairāk gorutinas bloķē viena otru, gaidot viena otru, un neviena no tām nevar turpināt izpildi. Visbiežāk tas notiek, strādājot ar mutexiem vai kanāliem.
Deadlock piemēri:
-
Mutexu bloķēšana dažādā secībā:
// Deadlock piemērs ar mutexiem var mu1 sync.Mutex var mu2 sync.Mutex func goroutine1() { mu1.Lock() // Iegūst mu1 time.Sleep(100 * time.Millisecond) // Mazs gaidīšanas laiks mu2.Lock() // Mēģina iegūt mu2 (ko tur goroutine2) fmt.Println("goroutine1 ieguva mu2") mu2.Unlock() mu1.Unlock() } func goroutine2() { mu2.Lock() // Iegūst mu2 time.Sleep(100 * time.Millisecond) // Mazs gaidīšanas laiks mu1.Lock() // Mēģina iegūt mu1 (ko tur goroutine1) fmt.Println("goroutine2 ieguva mu1") mu1.Unlock() mu2.Unlock() }Goroutine1 ieguva
mu1un gaidamu2. Goroutine2 ieguvamu2un gaidamu1. Abi gorutinas ir bloķētas. -
Sūtīšana nebuferētā kanālā bez saņēmēja:
// Deadlock piemērs ar kanālu func main() { ch := make(chan int) //go func() { // Ja neuzsāksim lasīšanas gorutinu, būs deadlock // <-ch //}() ch <- 1 // Sūtīšana kanālā bez aktīva saņēmēja fmt.Println("Nosūtīts kanālā") // Šī rinda netiks sasniegta }Sūtīšana nebuferētā kanālā bloķēs, līdz cita gorutina sāks lasīt no tā. Ja saņēmējs nav, notiks deadlock.
-
Lasīšana no kanāla bez sūtītāja (pēc slēgšanas vai tukša bufera):
// Deadlock piemērs ar kanāla lasīšanu func main() { ch := make(chan int, 1) // Buferēts kanāls ar 1 elementu ch <- 1 // Nosūtījām 1 close(ch) // Aizvērām kanālu <-ch // Lasījām 1 <-ch // Mēģinām vēlreiz lasīt no slēgta un tukša kanāla - deadlock }Lasīšana no slēgta, tukša vai atvērta, bet tukša nebuferizēta kanāla bez sūtītāja noved pie bloķēšanas.
Golang rīks var atpazīt noteiktus deadlock veidus (piemēram, kad visi bloķētie gorutinas gaida vienas gorutinas saņemšanu vai sūtīšanu), un šādā gadījumā programma negaidīti pārtrauks ar ziņojumu "fatal error: all goroutines are asleep - deadlock!". Tomēr ne visi deadlock veidi tiek automātiski atpazīti.
Lai novērstu deadlock, ir svarīgi:
- Saglabāt konsekventu mutexu iegūšanas kārtību.
- Nodrošināt, ka katram nebuferētam sūtījumam ir atbilstoša lasīšana, un otrādi.
- Darbā ar kanāliem izmantot
selectardefaultdaļu vai laika ierobežojumiem pēc nepieciešamības. - Rūpīgi pārvaldīt gorutinu dzīves ciklu un kanālu aizvēršanu.