Τι είναι το deadlock κατά την εργασία με goroutine;
sobes.tech AI
Απάντηση από AI
Ο deadlock (αδιέξοδο) είναι μια κατάσταση όπου δύο ή περισσότερες goroutines μπλοκάρουν η μία την άλλη περιμένοντας, και καμία από αυτές δεν μπορεί να συνεχίσει την εκτέλεση. Συχνότερα συμβαίνει κατά την εργασία με mutex ή κανάλια.
Παραδείγματα deadlock:
-
Μπλοκάρισμα mutex σε διαφορετική σειρά:
// Παράδειγμα deadlock με mutex var mu1 sync.Mutex var mu2 sync.Mutex func goroutine1() { mu1.Lock() // Κλειδώνει το mu1 time.Sleep(100 * time.Millisecond) // Περιμένει λίγο mu2.Lock() // Προσπαθεί να κλειδώσει το mu2 (κατειλημμένο από goroutine2) fmt.Println("goroutine1 απέκτησε mu2") mu2.Unlock() mu1.Unlock() } func goroutine2() { mu2.Lock() // Κλειδώνει το mu2 time.Sleep(100 * time.Millisecond) // Περιμένει λίγο mu1.Lock() // Προσπαθεί να κλειδώσει το mu1 (κατειλημμένο από goroutine1) fmt.Println("goroutine2 απέκτησε mu1") mu1.Unlock() mu2.Unlock() }Η goroutine1 έχει κλειδώσει το mu1 και περιμένει το mu2. Η goroutine2 έχει κλειδώσει το mu2 και περιμένει το mu1. Και οι δύο είναι μπλοκαρισμένες.
-
Αποστολή σε μη-buffered κανάλι χωρίς δέκτη:
// Παράδειγμα deadlock με κανάλι func main() { ch := make(chan int) //go func() { // Αν δεν ξεκινήσει μια goroutine ανάγνωσης, θα προκύψει deadlock // <-ch //}() ch <- 1 // Αποστολή στο κανάλι χωρίς ενεργό δέκτη fmt.Println("Αποστολή στο κανάλι") // Αυτή η γραμμή δεν θα επιτευχθεί }Η αποστολή σε μη-buffered κανάλι μπλοκάρει μέχρι να ξεκινήσει μια goroutine να διαβάσει από αυτό. Αν δεν υπάρχει δέκτης, προκύπτει deadlock.
-
Ανάγνωση από κανάλι χωρίς αποστολέα (μετά το κλείσιμο ή με άδειο buffer):
// Παράδειγμα deadlock κατά την ανάγνωση από κανάλι func main() { ch := make(chan int, 1) // Buffer κανάλι με 1 στοιχείο ch <- 1 // Αποστολή close(ch) // Κλείσιμο καναλιού <-ch // Ανάγνωση 1 <-ch // Προσπάθεια ανάγνωσης ξανά από κλειστό και άδειο κανάλι - deadlock }Η ανάγνωση από κλειστό και μη άδειο κανάλι θα ολοκληρωθεί με επιτυχία. Η ανάγνωση από κλειστό και άδειο κανάλι ή από ανοιχτό αλλά άδειο κανάλι χωρίς αποστολέα θα προκαλέσει μπλοκάρισμα.
Το runtime της Golang μπορεί να ανιχνεύσει ορισμένους τύπους deadlock (π.χ., όταν όλες οι μπλοκαρισμένες goroutines περιμένουν να λάβουν ή να στείλουν σε μια μόνο goroutine), και σε αυτή την περίπτωση το πρόγραμμα θα τερματίσει απότομα με το μήνυμα "fatal error: all goroutines are asleep - deadlock!". Ωστόσο, δεν μπορούν να ανιχνευθούν αυτόματα όλα τα deadlock.
Για την αποφυγή deadlock:
- Να διατηρείτε μια συνεπή σειρά κατά την απόκτηση mutex.
- Να διασφαλίζετε ότι κάθε αποστολή σε μη-buffered κανάλι έχει μια αντίστοιχη ανάγνωση, και το αντίστροφο.
- Να χρησιμοποιείτε
selectμεdefaultή χρονικά όρια όταν εργάζεστε με κανάλια, αν χρειάζεται. - Να διαχειρίζεστε προσεκτικά τον χρόνο ζωής των goroutines και το κλείσιμο των καναλιών.