Middle
Na co si dát pozor při práci s mutexy v Go?
sobes.tech AI
Odpověď od AI
Při práci s mutexy (sync.Mutex) v Go je důležité mít na paměti následující:
- Zámek a odemknutí: Mutex je nutné před přístupem ke sdíleným datům uzamknout (
Lock()) a po dokončení práce odemknout (Unlock()). Použitídefer mu.Unlock()ihned pomu.Lock()je dobrá praxe, která pomáhá zabránit zapomenutí odemknutí. - Grant synchronizace: Mutex poskytuje výhradní přístup k prostředku jednomu gorutině současně.
- Stav "zamčeno/odemčeno": Opakované volání
Lock()na již zamčeném mutexu způsobí zablokování volající gorutiny, dokud jiná gorutina neuvolní mutex. VoláníUnlock()na odemčeném mutexu způsobí paniku během běhu. - Nekopírovat mutexy: Struktura
sync.Mutexnení určena k kopírování po prvním použití. Předání mutexu hodnotou do funkce nebo kopírování struktury obsahující mutex může vést k nesprávné synchronizaci a panice. - Deadlock (zaseknutí): Vzniká, když dvě nebo více gorutin čekají na sebe, aby uvolnily prostředky. Typický scénář: gorutina A zamkne R1 a čeká na R2, zatímco gorutina B zamkne R2 a čeká na R1.
- Livelock (živé zamčení): Situace, kdy gorutiny neustále mění svůj stav v reakci na akce ostatních, ale nedělají užitečnou práci a neposunou se dopředu. To je vzácnější než deadlock.
- Hladem (starvation): Situace, kdy jedna nebo více gorutin nemůže získat přístup ke sdílenému prostředku kvůli jeho neustálému zámku jinými gorutinami. V Go mutexech není hladem garantován.
- Použití
sync.RWMutexpro čtení/zápis: Pokud většina operací je čtení a zápis je vzácný, může být efektivnějšísync.RWMutex. Umožňuje více gorutinám číst současně, ale při zápisu blokuje jak čtení, tak i jiné zápisy. - Krátké zámky: Snažte se držet zámky co nejkratší dobu. Čím déle je mutex zamčený, tím větší je pravděpodobnost, že ostatní gorutiny budou čekat, což snižuje paralelismus.
- Testování na závody: Použití vlajky
-racepři sestavování a spouštění testů (go test -race) pomáhá odhalit závody, které jsou často způsobeny nesprávným použitím mutexů.
Příklad použití defer:
import (
"sync"
)
type SafeCounter struct {
mu sync.Mutex
v map[string]int
}
// Inc bezpečně zvyšuje čítač pro daný klíč.
func (c *SafeCounter) Inc(key string) {
c.mu.Lock()
// Odkládáme odemknutí na konec funkce.
defer c.mu.Unlock()
c.v[key]++
}
// Value vrací aktuální hodnotu čítače pro daný klíč.
func (c *SafeCounter) Value(key string) int {
c.mu.Lock()
// Odkládáme odemknutí po získání hodnoty.
defer c.mu.Unlock()
return c.v[key]
}