Sobes.tech
Middle

Jak se vyhnout situaci vzájemného zablokování (deadlock) v programu v jazyce Go?

sobes.tech AI

Odpověď od AI

Vzájemné blokování v Go se nejčastěji vyskytuje při nesprávném použití mutexů a kanálů. Lze jej zabránit následujícími způsoby:

  • Řádné získávání mutexů: Při získávání více mutexů to vždy dělejte ve stejném pořadí ve všech gorutinách.
  • Časové limity pro zámky: Používejte kontexty s časovými limity při čekání na zámky nebo přijímání z kanálů, abyste zabránili nekonečnému čekání.
  • Nebufferované kanály: Pochopte, že nebufferované kanály vyžadují jak odesílatele, tak příjemce, aby mohli pokračovat v provádění. Nesprávné použití může vést ke zablokování.
  • Bufferované kanály: Správně zvolte velikost bufferu kanálu. Příliš malý buffer může vést ke zablokování, pokud odesílatelé a příjemci nejsou synchronizováni.
  • Použití select: Při práci s více kanály používejte operátor select s větví default nebo časovým limitem, aby nedošlo k zablokování při čekání na jeden kanál.
  • Analýza kódu: Používejte statickou analýzu (go vet, staticcheck) a nástroje pro detekci závodů (go run -race), které mohou také pomoci odhalit potenciální místa vzájemného blokování.
  • Hierarchie zdrojů: Pokud mají zdroje hierarchii, získávejte je shora dolů.
  • Vyvarujte se cyklických závislostí: Nevytvářejte situace, kdy gorutina A čeká na zdroj, který má B, a B čeká na zdroj, který má A.

Příklad použití select s časovým limitem:

import (
	"context"
	"time"
)

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

	select {
	case val := <-ch:
		// Zpracování hodnoty
		_ = val
	case <-ctx.Done():
		// Vypršel časový limit
	}
}