Канал принципиально отличается от мьютекса.
Правильный ответ с достаточным количеством деталей будет слишком длинным, поэтому давайте просто рассмотрим основные моменты, в частности, в отношении Go каналов:
- Канал Go обеспечивает типизированную передачу данных между параллельными подпрограммами (подпрограммами).
- A
sync.Mutex
обеспечивает взаимное исключение из общей памяти между параллельные подпрограммы (goroutines).
Передача данных представляет собой копирование значения некоторого типа T. Goroutine A помещает значение в канал:
var v T // v is a value of type T
...
ch <- v // put v's value into the channel
Когда и когда попытка вставить v
в канал блокирует , и что вы можете сделать с этим, если хотите, становится немного сложнее, но если канал буферизуется , тогда, по крайней мере, некоторые значения могут go сразу войти в него без какой-либо блокировки, так что отправляющая процедура может продолжаться. Если канал небуферизован , отправитель блокируется до тех пор, пока некоторая процедура приема не будет активно ожидать значения. (Иногда это желательно, а иногда - нет.)
Между тем, программа B извлекает значение из канала:
var w T // w is also a value of type T
...
w <- ch
или просто:
w :=<- ch
Опять же, когда и будет ли это блокировать, то, что вы можете сделать, когда вы должны что-то сделать и т. Д. c., Может стать сложным; но в простом случае это ожидает доступного значения - какая-то процедура должна выполнить ch <- v
, или уже сделала это, если канал буферизован - и затем копирует в переменную w
значение, которое был помещен в канал. Переменная v
могла измениться или даже полностью уничтожиться этой точкой. Значение было безопасно сохранено в канале, а теперь удалено из канала и помещено в переменную w
.
Go Каналы имеют некоторые дополнительные функции, такие как возможность закрыть канал, что предотвращает дальнейшую запись на него и доставляет уведомления об окончании данных для операций чтения. Это можно проверить с помощью чтения одного значения (w, ok <- ch
) и неявно протестировать в экземпляре for w := range ch
l oop.
A sync.Mutex
, напротив, просто позволяет вызвать Lock
и Unlock
. Он не содержит никаких значений в очереди (как буферизованный канал) и даже не имеет типа (кроме самого sync.Mutex
), который удерживает вас от случайной отправки float
чему-то ожидающему string
или чему-либо еще. Наличие этой блокировки позволяет двум или более подпрограммам использовать областей совместно используемой памяти , чтобы что-то сделать.
Реализация среды выполнения канала, скорее всего, нуждается в каком-то виде мьютекса. Это не должно быть sync.Mutex
само по себе: достаточно всего, что обеспечивает взаимное исключение. В реализации канала Go, которую вы, вероятно, используете , это не sync.Mutex
, а специализированный исполняемый мьютекс . (Обратите внимание, что эта ссылка ведет на указанную c строку, и эта строка может со временем устареть.) Поскольку некоторый код канала напрямую генерируется самим компилятором, подпрограммы времени выполнения здесь не должны использоваться: Ваш компилятор может быть другим. Однако изучение этой конкретной реализации может немного рассказать вам о том, что вы можете делать с каналами.
Мьютексы, как правило, намного проще , чем каналы. Чтобы увидеть пример, сравните объем кода в вышеприведенной реализации канала, которая не включает встроенные вставки компилятора, с этой конкретной Go реализацией sync.Mutex
исходного кода .