Sobes.tech
Middle

Kaip išvengti tarpusavio užblokavimo (deadlock) situacijos Go programoje?

sobes.tech AI

Atsakymas iš AI

Dalinė blokada Go dažniausiai atsiranda netinkamai naudojant mutuoklius ir kanalus. Jos išvengti galima šiais būdais:

  • Tvarkingas mutuoklių užėmimas: Kai užimate kelis mutuoklius, visada tai darykite tame pačiame tvarkoje visuose gorutinuose.
  • Laiko apribojimai užrakinimams: Naudokite kontekstus su laiko apribojimais, kai laukiate užraktų ar gaunate duomenis iš kanalų, kad išvengtumėte begalinio laukimo.
  • Neužpildyti kanalai: Supraskite, kad neužpildyti kanalai reikalauja, kad ir siuntėjas, ir gavėjas būtų aktyvūs, kad tęstųsi vykdymas. Netinkamas naudojimas gali sukelti užblokavimą.
  • Užpildyti kanalai: Teisingai pasirinkite kanalo dydį. Per mažas buferis gali sukelti užblokavimą, jei siuntėjai ir gavėjai nėra sinchronizuoti.
  • select naudojimas: Dirbant su keliais kanalais, naudokite select su default šaka arba laiko apribojimu, kad nesusidurtumėte su užblokavimu laukdami vieno kanalo.
  • Kodo analizė: Naudokite statinę analizę (go vet, staticcheck) ir įrankius duomenų konfliktų aptikimui (go run -race), kurie taip pat gali padėti nustatyti galimas tarpusavio blokavimo vietas.
  • Išteklių hierarchija: Jei ištekliai turi hierarchiją, juos užimkite iš viršaus į apačią.
  • Ciklinės priklausomybės vengimas: Nesukurkite situacijų, kai gorutina A laukia ištekliaus, užimto B, o B laukia ištekliaus, užimto A.

Pavyzdys naudojant select su laiko apribojimu:

import (
	"context"
	"time"
)

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

	select {
	case val := <-ch:
		// Apdoroti reikšmę
		_ = val
	case <-ctx.Done():
		// Įvyko laiko apribojimas
	}
}