Sobes.tech
Middle

Ako sa vyhnúť situácii vzájomného zablokovania (deadlock) v programe v Go?

sobes.tech AI

Odpoveď od AI

Vzájomné blokovanie v Go najčastejšie vzniká nesprávnym použitím mutexov a kanálov. Dá sa mu predísť nasledujúcimi spôsobmi:

  • Usporiadané získavanie mutexov: Pri získavaní viacerých mutexov to vždy robte v rovnakom poradí vo všetkých gorutinách.
  • Timeouty pre zámky: Používajte kontexty s timeoutmi pri čakaní na zámky alebo prijímaní z kanálov, aby ste predišli nekonečnému čakaniu.
  • Nebufferované kanály: Pochopte, že nebufferované kanály vyžadujú ako odosielateľa, tak príjemcu, aby mohli pokračovať v vykonávaní. Nesprávne použitie môže viesť k zablokovaniu.
  • Bufferované kanály: Správne zvoľte veľkosť bufferu kanála. Príliš malý buffer môže viesť k zablokovaniu, ak odosielatelia a príjemcovia nie sú synchronizovaní.
  • Použitie select: Pri práci s viacerými kanálmi používajte operátor select s default vetvou alebo timeoutom, aby ste sa nezablokovali na čakaní na jeden kanál.
  • Analýza kódu: Používajte statickú analýzu (go vet, staticcheck) a nástroje na detekciu závodov (go run -race), ktoré môžu tiež pomôcť odhaliť potenciálne miesta vzájomného blokovania.
  • Hierarchia zdrojov: Ak majú zdroje hierarchiu, získavajte ich odhora nadol.
  • Vyhýbajte sa cyklickým závislostiam: Nezabudnite vytvárať situácie, v ktorých gorutina A čaká na zdroj, ktorý má B, a B čaká na zdroj, ktorý má A.

Príklad použitia select s timeoutom:

import (
	"context"
	"time"
)

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

	select {
	case val := <-ch:
		// Spracovanie hodnoty
		_ = val
	case <-ctx.Done():
		// Vypršal časový limit
	}
}