Co je to deadlock při práci s goroutine?
sobes.tech AI
Odpověď od AI
Deadlock (zaseknutí) je situace, kdy dvě nebo více gorutin blokují navzájem, čekají na sebe, a žádná z nich nemůže pokračovat. Nejčastěji k tomu dochází při práci s mutexy nebo kanály.
Příklady deadlocku:
-
Zámky mutexů v různém pořadí:
// Příklad deadlocku s mutexy var mu1 sync.Mutex var mu2 sync.Mutex func goroutine1() { mu1.Lock() // Získá mu1 time.Sleep(100 * time.Millisecond) // Čeká trochu mu2.Lock() // Pokouší se získat mu2 (který drží goroutine2) fmt.Println("goroutine1 získal mu2") mu2.Unlock() mu1.Unlock() } func goroutine2() { mu2.Lock() // Získá mu2 time.Sleep(100 * time.Millisecond) // Čeká trochu mu1.Lock() // Pokouší se získat mu1 (který drží goroutine1) fmt.Println("goroutine2 získal mu1") mu1.Unlock() mu2.Unlock() }Goroutine1 získala
mu1a čeká namu2. Goroutine2 získalamu2a čeká namu1. Obě gorutiny jsou zablokované. -
Odeslání do nevybaveného kanálu bez příjemce:
// Příklad deadlocku s kanálem func main() { ch := make(chan int) //go func() { // Pokud nespustíme gorutinu pro čtení, dojde k deadlocku // <-ch //}() ch <- 1 // Odeslání do kanálu bez aktivního příjemce fmt.Println("Odesláno do kanálu") // Tento řádek nebude dosažen }Odeslání do nevybaveného kanálu se zablokuje, dokud jiná gorutina nezačne číst z něj. Pokud není žádný příjemce, dojde k deadlocku.
-
Čtení z kanálu bez odesílatele (po uzavření nebo prázdný bufferovaný):
// Příklad deadlocku při čtení z kanálu func main() { ch := make(chan int, 1) // Bufferovaný kanál na 1 prvek ch <- 1 // Odeslali jsme 1 close(ch) // Uzavřeli kanál <-ch // Přečetli 1 <-ch // Pokoušíme se přečíst znovu z uzavřeného a prázdného kanálu - deadlock }Čtení z uzavřeného nevybaveného kanálu skončí úspěšně. Čtení z uzavřeného a prázdného nebo z otevřeného, ale prázdného nevybaveného kanálu bez odesílatele povede k blokování.
Golang runtime může detekovat určité typy deadlocků (například když všechny zablokované gorutiny čekají na příjem nebo odeslání jediného gorutiny), a v takovém případě program neočekávaně skončí s hlášením "fatal error: all goroutines are asleep - deadlock!". Nicméně, ne všechny deadlocky mohou být automaticky detekovány.
Pro prevenci deadlocků je důležité:
- Dodržovat konzistentní pořadí získávání mutexů.
- Zajistit, že pro každé odeslání do nevybaveného kanálu existuje odpovídající příjem, a naopak.
- Při práci s kanály používat
selectsdefaultvětví nebo časové limity podle potřeby. - Pečlivě řídit životnost gorutin a uzavírání kanálů.