Вы можете, если хотите, рассматривать канал как своего рода почтовый ящик (возможно, со специальными возможностями телепортации, например, портал из игрового портала ).
An unbuffered канал - это почтовый ящик, в котором вообще нет места для каких-либо пакетов. Чтобы кто-то отправил посылку по почте (отправил значение), он должен дождаться, пока рука получателя не высунется из почтового ящика. Затем они могут бросить посылку в руку, которая вернется обратно в почтовый ящик, забрав посылку с собой. Если кто-то в очереди, вы должны встать в очередь за кем-то еще.
A буферизованный канал - это почтовый ящик, который может содержать один или несколько пакетов. Чтобы отправить посылку, зайдите в линию, если она есть. Когда вы достигнете головы линии, вы можете посмотреть на коробку. Если есть место для вашей посылки, вставьте ее и продолжайте заниматься своими делами. Если нет, вы можете подождать, пока освободится место, а затем положить пакет и продолжить заниматься своим делом.
Таким образом, существует общая схема отправки:
- Получить в очередиесли вам нужно.
- Когда вы достигнете головы очереди, положите свой пакет, если есть место, в противном случае дождитесь места - или, если небуферизованный канал, чтобы кто-то пришел к другому (получите) и положите руку, чтобы получить.
Между тем, если вы хотите получить из канала, вы, при необходимости, встаете в очередь, как и для отправки. Как только вы окажетесь во главе очереди, вы можете взять пакет из коробки или - для небуферизованного канала - подождать, когда ваша рука торчит из другой стороны коробки без места, чтобы кто-топодойди и вложи в это что-нибудь.
Каждая горутина, по этой аналогии, похожа на человека или иди суслик . Он (или он или она, или любое местоимение, которое вы предпочитаете) может стоять в очереди, если это необходимо, и помещать вещи в один из этих каналов. Ваша программа начинается с одной программы, которая вызывает main
.
. В вашем коде вы запускаете вторую программу, которая начинается с multiplyByTwo
. Эта одна программа ожидает - один раз - номера, который будет отображаться в канале, или, в этом случае, кого-то, кто ожидает, чтобы отправить номер, так как канал не буферизован. Затем он удваивает (единственное) полученное число, печатает результат и выходит / умирает / оказывается похороненным, чтобы никогда не существовать снова.
Между тем, ваш main
ждет, пока кто-то получит - это будет вашвторая программа - пока она не будет готова принять число 3
, которое находится в n
. Эта часть успешна. Затем ваш main
ожидает другого приема, чтобы он мог отправить константу 3
.
Пока ваш main
ожидает, ваша другая программа выполняет свою работу - или, возможно, закончила свою работу - ивыходы. Теперь во всей системе есть только один «человек» (или суслик, или кто-то еще), ожидающий, пока второй человек - который не существует и никогда не будет рожден - придет, чтобы взять число. Базовая система Go может сказать, что это событие никогда не произойдет, и вот когда вы получите сообщение:
fatal error: all goroutines are asleep - deadlock!
(это также завершает программу).
БуракОтвет Сердара показывает, как у вас может быть ваша вторая программа продолжайте читать номера с канала. Это порождает новую проблему: как вы говорите второму горутину, что больше нет номеров? Ответ в том, что вы можете закрыть канал с помощью close
.
Если мы будем придерживатьсяПо аналогии с почтовым ящиком вы можете подумать о закрытии канала, как о размещении специальной наклейки или ярлыка на отправляющей стороне канала. Это препятствует тому, чтобы кто-либо делал дальнейшие вставки значений. Любые пакеты, которые в канале уже безопасны - они остаются там до тех пор, пока их не получат, но никакие пакеты new не могут войти. На стороне получателя легко заметить разницумежду упаковкой и этой специальной наклейкой: поэтому, когда вы сталкиваетесь с «закрытой» наклейкой, вы знаете, что больше никаких ценностей не будет. Если канал небуферизован, вы можете сразу увидеть эту наклейку. Если он буферизирован, вам сначала нужно будет удалить все существующие пакеты, прежде чем вы сможете его увидеть.
Обычно отправитель должен закрыть канал, чтобы получатели знали, что они будутне получить больше ничего от этого. (Во многих конкретных случаях вы можете уйти, не закрывая канал. В частности, если подпрограмма, выполняющая main
, возвращается из своего вызова к main
, все остальные подпрограммы более или менее умирают немедленно.)
Обратите внимание, что после закрытия no отправитель может закрыть канал снова , поэтому это означает, что если у вас есть один канал, который вы разделяете только для нескольких отправителей, толькоодин из них может закрыть канал! Сделать правильную работу довольно сложно, поэтому чаще избегать совместного использования канала более чем одной записывающей программой, подобной этой.