# Сравнение: Мьютексы и Каналы в Go

Go предлагает два подхода к синхронизации и обмену данными между горутинами:

- 🔒 **Мьютексы (Mutex)** — синхронизация доступа к общей памяти
- 📬 **Каналы (Channels)** — передача данных без разделяемой памяти

---

## <a id="bkmrk--1"></a>🔒 Мьютексы (`sync.Mutex`)

Мьютекс позволяет **гарантировать, что только одна горутина** в момент времени имеет доступ к критической секции кода.

### <a id="bkmrk--2"></a>✅ Пример:

```
import "sync"

type Counter struct {
    m  sync.Mutex
    v  int
}

func (c *Counter) Inc() {
    c.m.Lock()
    c.v++
    c.m.Unlock()
}

```

### <a id="bkmrk--3"></a>🧠 Когда использовать мьютекс:

- Множественные горутины читают/пишут переменную
- Работа с `map`, `slice` без гонки данных
- Критический код, который нельзя выполнять одновременно

---

## <a id="bkmrk--5"></a>📬 Каналы (`chan`)

Каналы передают данные между горутинами. Это позволяет **избежать прямого доступа к разделяемой памяти**.

### <a id="bkmrk--6"></a>✅ Пример:

```
func worker(jobs <-chan int, results chan<- int) {
    for job := range jobs {
        results <- job * 2
    }
}

func main() {
    jobs := make(chan int, 5)
    results := make(chan int, 5)

    go worker(jobs, results)

    jobs <- 1
    jobs <- 2
    close(jobs)

    fmt.Println(<-results)
    fmt.Println(<-results)
}

```

### <a id="bkmrk--7"></a>🧠 Когда использовать каналы:

- Потоковая обработка данных
- Логика “продюсер/консюмер”
- Синхронизация начала/окончания работы
- Архитектура “fan-in”, “fan-out”

---

## <a id="bkmrk--9"></a>⚖️ Сравнение

<table class="table table-striped table-bordered" id="bkmrk-%D0%9A%D1%80%D0%B8%D1%82%D0%B5%D1%80%D0%B8%D0%B9-%D0%9C%D1%8C%D1%8E%D1%82%D0%B5%D0%BA%D1%81%D1%8B-%D0%9A%D0%B0"><thead><tr><th>Критерий</th><th>Мьютексы</th><th>Каналы</th></tr></thead><tbody><tr><td>Принцип</td><td>Общая память</td><td>Сообщения</td></tr><tr><td>Сложность</td><td>Низкая, но с рисками</td><td>Чище, но требует дизайна</td></tr><tr><td>Поддержка `pprof`</td><td>Да (через `mutex`)</td><td>Частично (горутины)</td></tr><tr><td>Предотвращение гонок</td><td>Да</td><td>Да</td></tr><tr><td>Применение</td><td>Быстрый доступ</td><td>Асинхронные операции</td></tr></tbody></table>

---

## <a id="bkmrk--11"></a>🧪 Рекомендация от Go-разработчиков

> **“Не общайся через общую память — делись памятью через общение.”**

Используй **каналы**, если можешь выразить логику через них, и **мьютексы**, когда нужна низкоуровневая производительность.

---

## <a id="bkmrk--13"></a>📌 Итог

| Хочешь максимальную скорость | Используй `sync.Mutex` |  
| Хочешь безопасный обмен | Используй `chan` |  
| Хочешь лучшее из двух миров | Используй `sync.Map`, `sync.Once`, `sync.WaitGroup` при необходимости |

---

## <a id="bkmrk--15"></a>🧰 Дополнительные инструменты из `sync`

Go также предоставляет удобные примитивы для управления конкурентностью:

---

### <a id="bkmrk--17"></a>🔁 `sync.Once` — выполнить только один раз

Позволяет гарантировать, что определённый код будет выполнен **только один раз**, даже если вызывается из нескольких горутин.

```
var once sync.Once

func initConfig() {
    once.Do(func() {
        fmt.Println("Конфигурация инициализирована")
    })
}

```

Используется для ленивой инициализации, подключения к БД, загрузки конфигов.

---

### <a id="bkmrk--19"></a>👥 `sync.WaitGroup` — дождаться завершения горутин

Позволяет дождаться, пока все горутины завершатся.

```
var wg sync.WaitGroup

for i := 0; i < 5; i++ {
    wg.Add(1)
    go func(id int) {
        defer wg.Done()
        fmt.Printf("Горутина %d завершена
", id)
    }(i)
}

wg.Wait()
fmt.Println("Все горутины завершились")

```

---

### <a id="bkmrk--21"></a>🗺️ `sync.Map` — потокобезопасная map

Альтернатива обычной `map`, не требующая ручной синхронизации.

```
var sm sync.Map

sm.Store("foo", 42)
val, ok := sm.Load("foo")
if ok {
    fmt.Println("Значение:", val)
}

sm.Range(func(key, value any) bool {
    fmt.Printf("%v = %v
", key, value)
    return true
})

```

Подходит для кэширования, счётчиков, безопасной общей памяти между горутинами.

---

## <a id="bkmrk--23"></a>📌 Вывод:

<table class="table table-striped table-bordered" id="bkmrk-%D0%98%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BC%D0%B5%D0%BD%D1%82-%D0%9D%D0%B0%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8"><thead><tr><th>Инструмент</th><th>Назначение</th></tr></thead><tbody><tr><td>`sync.Mutex`</td><td>Защита разделяемых данных</td></tr><tr><td>`sync.Once`</td><td>Инициализация кода только один раз</td></tr><tr><td>`sync.WaitGroup`</td><td>Ожидание завершения группы горутин</td></tr><tr><td>`sync.Map`</td><td>Потокобезопасный ассоциативный массив</td></tr></tbody></table>