Kas yra deadlock dirbant su goroutine?
sobes.tech AI
Atsakymas iš AI
Deadlock (užstrigimas) — tai situacija, kai dvi ar daugiau gorutinos blokuoja viena kitą, laukdamos viena kitos, ir nė viena jų negali tęsti vykdymo. Dažniausiai tai įvyksta dirbant su mutexais arba kanalais.
Deadlock pavyzdžiai:
-
Mutexų užrakinimas skirtinga tvarka:
// Deadlock pavyzdys su mutexais var mu1 sync.Mutex var mu2 sync.Mutex func goroutine1() { mu1.Lock() // Užrakina mu1 time.Sleep(100 * time.Millisecond) // Trumpo laiko laukimas mu2.Lock() // Bando užrakinti mu2 (kurį laiko goroutine2) fmt.Println("goroutine1 įgijo mu2") mu2.Unlock() mu1.Unlock() } func goroutine2() { mu2.Lock() // Užrakina mu2 time.Sleep(100 * time.Millisecond) // Trumpo laiko laukimas mu1.Lock() // Bando užrakinti mu1 (kurį laiko goroutine1) fmt.Println("goroutine2 įgijo mu1") mu1.Unlock() mu2.Unlock() }Goroutine1 įgijo
mu1ir laukiamu2. Goroutine2 įgijomu2ir laukiamu1. Abi gorutinos yra užblokuotos. -
Žinutės siuntimas nebuferizuotu kanalu be gavėjo:
// Deadlock pavyzdys su kanalu func main() { ch := make(chan int) //go func() { // Jei neužvesime skaitymo gorutinos, įvyks deadlock // <-ch //}() ch <- 1 // Siuntimas į kanalą be aktyvaus gavėjo fmt.Println("Išsiųsta į kanalą") // Šis eilutė nebus pasiekta }Siuntimas nebuferizuotu kanalu blokuos, kol kita gorutina pradės skaityti iš jo. Jei nėra gavėjo, įvyksta deadlock.
-
Skaitymas iš kanalo be siuntėjo (po uždarymo arba tuščio buferio):
// Deadlock pavyzdys skaitant iš kanalo func main() { ch := make(chan int, 1) // Buferuotas kanalas su 1 elementu ch <- 1 // Siuntėme 1 close(ch) // Uždarėme kanalą <-ch // Perskaitėme 1 <-ch // Bandome dar kartą skaityti iš uždaryto ir tuščio kanalo - deadlock }Skaitymas iš uždaryto, tuščio kanalo bus sėkmingas. Skaitymas iš uždaryto ir tuščio arba atviro, bet tuščio nebuferizuoto kanalo be siuntėjo sukels blokavimą.
Golang vykdymo aplinka gali aptikti tam tikrus deadlock tipus (pavyzdžiui, kai visi užblokuoti gorutinos laukia vienos gorutinos priėmimo ar siuntimo), ir tokiu atveju programa netikėtai sustos su pranešimu "fatal error: all goroutines are asleep - deadlock!". Tačiau ne visi deadlockai gali būti automatiškai aptikti.
Deadlockų prevencijai svarbu:
- Laikytis nuoseklaus mutexų įsigijimo tvarkos.
- Užtikrinti, kad kiekvienas nebuferizuotas siuntimas turi atitinkamą skaitymą, ir atvirkščiai.
- Dirbant su kanalais naudoti
selectsudefaultgrupe arba laiko apribojimais pagal poreikį. - Atsargiai valdyti gorutinos gyvavimo ciklą ir kanalų uždarymą.