Ce este un deadlock atunci când lucrezi cu goroutine?
sobes.tech AI
Răspuns de la AI
Blocajul (deadlock) este o situație în care două sau mai multe goroutines se blochează reciproc așteptând una pe cealaltă, și niciuna dintre ele nu poate continua execuția. Apare cel mai des atunci când se lucrează cu mutex-uri sau canale.
Exemple de deadlock-uri:
-
Blocarea mutex-urilor în ordine diferită:
// Exemplu de deadlock cu mutex-uri var mu1 sync.Mutex var mu2 sync.Mutex func goroutine1() { mu1.Lock() // Blochează mu1 time.Sleep(100 * time.Millisecond) // Așteaptă puțin mu2.Lock() // Încearcă să blocheze mu2 (ocupat de goroutine2) fmt.Println("goroutine1 a dobândit mu2") mu2.Unlock() mu1.Unlock() } func goroutine2() { mu2.Lock() // Blochează mu2 time.Sleep(100 * time.Millisecond) // Așteaptă puțin mu1.Lock() // Încearcă să blocheze mu1 (ocupat de goroutine1) fmt.Println("goroutine2 a dobândit mu1") mu1.Unlock() mu2.Unlock() }Goroutine1 a blocat
mu1și așteaptămu2. Goroutine2 a blocatmu2și așteaptămu1. Ambele goroutines sunt blocate. -
Trimitere într-un canal fără buffer fără receptor:
// Exemplu de deadlock cu canal func main() { ch := make(chan int) //go func() { // Dacă nu se pornește o goroutine pentru citire, va apărea deadlock // <-ch //}() ch <- 1 // Trimitere în canal fără receptor activ fmt.Println("Trimis în canal") // Această linie nu va fi atinsă }Trimiterea într-un canal fără buffer se blochează până când o altă goroutine începe să citească din el. Dacă nu există receptor, apare deadlock.
-
Citirea dintr-un canal fără emițător (după închidere sau cu buffer gol):
// Exemplu de deadlock la citirea dintr-un canal func main() { ch := make(chan int, 1) // Canal bufferizat cu 1 element ch <- 1 // Trimis close(ch) // Închide canalul <-ch // Citește 1 <-ch // Încearcă să citească din nou dintr-un canal închis și gol - deadlock }Citirea dintr-un canal închis și nevid se va termina cu succes. Citirea dintr-un canal închis și gol sau dintr-un canal deschis, dar gol, fără emițător va duce la blocare.
Runtime-ul Golang poate detecta anumite tipuri de deadlock-uri (de exemplu, când toate goroutine-urile blocate așteaptă să primească sau să trimită către o singură goroutine), și în acest caz programul se va încheia brusc cu mesajul "fatal error: all goroutines are asleep - deadlock!". Totuși, nu toate deadlock-urile pot fi detectate automat.
Pentru a preveni deadlock-urile, este important:
- Să păstrezi o ordine consecventă în capturarea mutex-urilor.
- Să te asiguri că pentru fiecare trimitere într-un canal fără buffer există o citire corespunzătoare, și invers.
- Să folosești
selectcudefaultsau timeout-uri atunci când lucrezi cu canale, dacă este necesar. - Să gestionezi cu grijă durata de viață a goroutine-urilor și închiderea canalelor.