Когда вы используете небуферизованный канал, goroutine блокируется во время записи, пока кто-то не прочитает.В вашем первом фрагменте есть небуферизованный канал и единственная программа (основная программа).Поэтому, когда вы пытаетесь написать:
ch <- 1
Никто еще не читает с канала.Основная процедура заблокирована, и эта строка никогда не выполняется:
fmt.Println(<-ch)
Вот почему вы получили ошибку взаимоблокировки.
Во втором примере вы все еще используете небуферизованный канал, что означаетОперация записи блокирует выполнение программы.Но, используя go
, вы запускаете вторую программу.Это означает, что даже если эта новая программа будет заблокирована во время записи (в вашей функции assign
), основная программа будет продолжать работать, и fmt.Println(<-ch)
будет выполнена и выполнит чтение (что, в свою очередь, разблокирует фоновую программу и assign
функция, наконец, достигнет конца).
Чтобы получить больше понимания о каналах и процедурах, этот фрагмент даст тот же результат (что и ваш второй фрагмент):
package main
import "fmt"
func print(ch chan int) {
fmt.Println(<-ch)
}
func main() {
ch := make(chan int)
go print(ch)
ch <- 1
}
Когда вы работаетес буферизованным каналом (третий фрагмент) вы можете выполнять операции записи N
без блокировки процедуры (где N
- размер буфера).Вот почему в вашем примере вы сделали 2 записи без блокировки и можете прочитать их позже.Но если ваш буфер меньше, чем количество операций записи, и никто не выполняет чтение, вы попадете в те же проблемы с блокировкой (см. Объяснение фрагментов 1 и 2).