Мьютекс удобен для защиты разделяемого состояния (общий map, счётчик, буфер): проще и часто производительнее. Каналы лучше подходят для координации горутин и передачи данных (pipeline, fan-out, сигналы отмены).
var mu sync.Mutex
var cache map[string]string
func Get(k string) string {
mu.Lock()
defer mu.Unlock()
return cache[k]
}
jobs := make(chan int, 100)
go producer(jobs)
go worker(jobs)
// или: выборка из нескольких каналов, таймауты, отмена
Девиз "share memory by communicating" не запрещает мьютексы - он про то, что каналы часто делают программу понятнее. Для простого кеша или счётчика мьютекс идиоматичен.