Sobes.tech
Middle

Na čo si treba dávať pozor pri práci s mutexmi v Go?

sobes.tech AI

Odpoveď od AI

Pri práci s mutexmi (sync.Mutex) v Go je dôležité mať na pamäti nasledujúce:

  • Zámok a odomknutie: Mutex je nutné pred prístupom ku zdieľaným dátam uzamknúť (Lock()) a po dokončení práce ich odomknúť (Unlock()). Použitie defer mu.Unlock() ihneď po mu.Lock() je dobrá prax na zabránenie zabudnutému odomknutiu.
  • Grant synchronizácie: Mutex poskytuje výhradný prístup k zdroju jednému gorutinu súčasne.
  • Stav "zamknuté/odomknuté": Opakované volanie Lock() na už zamknutom mutexe spôsobí zablokovanie volajúcej gorutiny, kým iná gorutina neuvoľní mutex. Volanie Unlock() na odomknutom mutexe spôsobí pániku počas behu.
  • Nekopírujte mutexy: Štruktúra sync.Mutex nie je určená na kopírovanie po prvom použití. Prenos mutexu hodnotou do funkcie alebo kopírovanie štruktúry obsahujúcej mutex môže viesť k nesprávnej synchronizácii a pánike.
  • Deadlock (zaseknutie): Vzniká, keď dve alebo viac gorutín čakajú na seba, aby uvoľnili zdroje. Typický scenár: gorutina A zablokuje zdroj R1 a čaká na R2, zatiaľ čo gorutina B zablokuje R2 a čaká na R1.
  • Livelock (živé zablokovanie): Situácia, keď gorutiny neustále menia svoj stav v reakcii na akcie ostatných, ale nerobia užitočnú prácu a nepostupujú dopredu. Toto je zriedkavejšie ako deadlock.
  • Hladovanie (starvation): Situácia, keď jedna alebo viac gorutín nemôže získať prístup ku zdieľanému zdroju kvôli jeho neustálemu zámku inými gorutinami. V Go mutexoch nie je hladovanie garantované.
  • Použitie sync.RWMutex pre čítanie/zápis: Ak väčšina operácií je čítanie a zápis je zriedkavý, môže byť efektívnejší sync.RWMutex. Umožňuje viacerým gorutinám čítať súčasne, ale pri zápise blokuje ako čítanie, tak aj iné zápisy.
  • Krátke zámky: Snažte sa držať zámky čo najkratšie. Čím dlhšie je mutex zamknutý, tým väčšia je pravdepodobnosť, že ostatné gorutiny budú čakať, čo znižuje paralelizmus.
  • Testovanie na závody: Použitie vlajky -race pri kompilácii a spustení testov (go test -race) pomáha odhaliť závody, často spôsobené nesprávnym použitím mutexov.

Príklad použitia defer:

import (
	"sync"
)

type SafeCounter struct {
	mu sync.Mutex
	v  map[string]int
}

// Inc bezpečne zvyšuje čítač pre daný kľúč.
func (c *SafeCounter) Inc(key string) {
	c.mu.Lock()
	// Odkladáme uvoľnenie na koniec funkcie.
	defer c.mu.Unlock()
	c.v[key]++
}

// Value vracia aktuálnu hodnotu čítača pre daný kľúč.
func (c *SafeCounter) Value(key string) int {
	c.mu.Lock()
	// Odkladáme uvoľnenie po získaní hodnoty.
	defer c.mu.Unlock()
	return c.v[key]
}