Sobes.tech
Middle

Hoe kun je een deadlock-situatie in een Go-programma voorkomen?

sobes.tech AI

Antwoord van AI

Wederzijdse blokkering in Go ontstaat meestal door verkeerd gebruik van mutexen en kanalen. Dit kan worden voorkomen met de volgende methoden:

  • Geordend verkrijgen van mutexen: Wanneer je meerdere mutexen verkrijgt, doe dit dan altijd in dezelfde volgorde in alle goroutines.
  • Time-outs voor blokkades: Gebruik contexten met time-outs bij het wachten op blokkades of het ontvangen van kanalen, om eindeloos wachten te voorkomen.
  • Onbufferde kanalen: Begrijp dat onbufferde kanalen zowel zender als ontvanger nodig hebben om door te gaan. Onjuist gebruik kan leiden tot blokkering.
  • Gebufferde kanalen: Kies de juiste buffermaat voor het kanaal. Een te kleine buffer kan leiden tot blokkering als zenders en ontvangers niet gesynchroniseerd zijn.
  • Gebruik van select: Bij het werken met meerdere kanalen, gebruik de select-operator met een default-tak of time-out, zodat je niet op één kanaal blijft wachten.
  • Code-analyse: Gebruik statische analyse (go vet, staticcheck) en tools om racecondities (go run -race) te detecteren, die ook kunnen helpen bij het identificeren van potentiële plaatsen van wederzijdse blokkeringen.
  • Resource-hiërarchie: Als resources een hiërarchie hebben, verkrijg ze dan van boven naar beneden.
  • Vermijd cyclische afhankelijkheden: Creëer geen situaties waarin goroutine A wacht op een resource die door B wordt vastgehouden, en B wacht op een resource die door A wordt vastgehouden.

Voorbeeld van gebruik van select met time-out:

import (
	"context"
	"time"
)

func voorbeeld(ch chan int) {
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
	defer cancel()

	select {
	case val := <-ch:
		// Verwerk waarde
		_ = val
	case <-ctx.Done():
		// Time-out opgetreden
	}
}