Middle
Comment éviter une situation de blocage mutuel (deadlock) dans un programme en Go?
sobes.tech IA
Réponse de l'IA
Le blocage mutuel en Go survient le plus souvent en raison d'une utilisation incorrecte des mutex et des canaux. Il peut être évité par les moyens suivants :
- Capture ordonnée des mutex : Lors de la capture de plusieurs mutex, faites-le toujours dans le même ordre dans toutes les goroutines.
- Timeouts pour les blocages : Utilisez des contextes avec des timeouts lors de l'attente de blocages ou de la réception depuis des canaux, pour éviter une attente infinie.
- Canaux non tamponnés : Comprenez que les canaux non tamponnés nécessitent à la fois l'expéditeur et le récepteur pour continuer l'exécution. Une utilisation incorrecte peut entraîner un blocage.
- Canaux tamponnés : Choisissez correctement la taille du tampon du canal. Un tampon trop petit peut entraîner un blocage si les émetteurs et les récepteurs ne sont pas synchronisés.
- Utilisation de
select: Lors de la gestion de plusieurs canaux, utilisez l'opérateurselectavec une branchedefaultou un timeout, pour ne pas se bloquer en attendant un seul canal. - Analyse du code : Utilisez l'analyse statique (
go vet,staticcheck) et des outils pour détecter les conditions de course (go run -race), qui peuvent également aider à identifier les points potentiels de blocage mutuel. - Hiérarchie des ressources : Si les ressources ont une hiérarchie, acquérez-les de haut en bas.
- Éviter les dépendances cycliques : Ne créez pas de situations où la goroutine A attend une ressource occupée par B, et B attend une ressource occupée par A.
Exemple d'utilisation de select avec timeout :
import (
"context"
"time"
)
func exemple(ch chan int) {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
select {
case val := <-ch:
// Traitement de la valeur
_ = val
case <-ctx.Done():
// Timeout survenu
}
}