Sobes.tech
Middle

Šta treba imati na umu prilikom rada sa mutexima u Go?

sobes.tech АИ

Одговор од АИ

При раду са мјутексима (sync.Mutex) у Go-у важно је запамтити следеће:

  • Загрљај и ослобађање: Мјутекс је обавезно треба загрлити (Lock()) пре приступа до дељених података и ослободити (Unlock()) након завршетка рада са њима. Коришћење defer mu.Unlock() одмах после mu.Lock() је добра пракса за спречавање заборављеног ослобађања.
  • Грант синхронизације: Мјутекс пружа искључив приступ ресурсу једном горутину у исто време.
  • Стање "заглављено/откључано": Поновно позивање Lock() на већ заглављеном мјутексу ће блокирати позивајућу горутину док друга горутина не ослободи мјутекс. Позив Unlock() на откључаном мјутексу изазива панику током извршавања.
  • Не копирати мјутексе: Структура sync.Mutex није намењена за копирање након прве употребе. Пренос мјутекса по вредности у функцију или копирање структуре која садржи мјутекс може довести до неисправне синхронизације и панике.
  • Deadlock (задржавање): Настане када две или више горутина чекају једна другу да ослободе ресурсе. Типичан сценарио: горутина A блокира ресурс R1 и чека R2, док горутина B блокира R2 и чека R1.
  • Livelock (живи блок): Ситуација када горутине стално мењају стање у одговору на акције других, али не обављају корисан рад и не напредују. Ово је ређи случај од deadlock-а.
  • Глад (starvation): Ситуација када једна или више горутина не могу добити приступ до дељеног ресурса због сталног заузимања од стране других. У Go мјутексима, глад не је гарантована.
  • Користите sync.RWMutex за читање/писање: Ако је већина операција читање, а запис је реткост, sync.RWMutex може бити ефикаснији. Омогућава више горутина да читају истовремено, али при запису блокира и читање и друге записе.
  • Кратки блокирања: Трудите се да држите блокирања што краће. Што дуже мјутекс буде закључан, то је већа вероватноћа да ће друге горутине чекати, што смањује паралелност.
  • Тестирање на трке: Коришћење флага -race приликом компилације и покретања тестова (go test -race) помаже у откривању трка, често узрокованих неправилном употребом мјутекси.

Пример коришћења defer:

import (
	"sync"
)

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

// Inc безопасно повећава бројач за датог кључа.
func (c *SafeCounter) Inc(key string) {
	c.mu.Lock()
	// Одлажемо ослобађање до изласка из функције.
	defer c.mu.Unlock()
	c.v[key]++
}

// Value враћа тренутну вредност бројача за датог кључа.
func (c *SafeCounter) Value(key string) int {
	c.mu.Lock()
	// Одлажемо ослобађање након добијања вредности.
	defer c.mu.Unlock()
	return c.v[key]
}