использовать канал
Распространенное использование связи между сопрограммами, отправка значений вchannel
, внешнийchannel
перенимать.
func t1() {
ch := make(chan int)
go func() {
ch <- 1
}()
// <-ch // 导致下面语句阻塞
fmt.Println("channel int", <-ch)
}
channel int 1
channel
вспомогательный буфер
func t2() {
ch := make(chan int, 3)
go func() {
ch <- 1
ch <- 2
ch <- 3
ch <- 4 // 会阻塞写不入, 除非ch已接收
close(ch) // 关闭后不能再写入, 并且缓冲区内为空时则返回零值
}()
fmt.Println("buffer channel int",
<-ch,
<-ch,
<-ch,
<-ch,
<-ch)
}
buffer channel int 1 2 3 4 0
select
Он специально настроен для трубопровода
func t3() {
ch1 := make(chan int)
ch2 := make(chan struct{})
go func() {
ch1 <- 2
}()
select {
case <-ch1:
fmt.Println("select here is ch1")
case <-ch2:
fmt.Println("select here is ch2")
}
}
select here is ch1
использоватьfor
func t4() {
ch := make(chan int, 5)
go func() {
for i:=1; i<=5; i++ {
time.Sleep(time.Millisecond * 10)
ch <- i
}
}()
for v := range ch { // 会阻塞
fmt.Println("for channel ", v)
if v == 5 {
break
}
}
}
for channel 1
for channel 2
for channel 3
for channel 4
for channel 5
использовать одновременноselect
иfor
func t5() {
chPrint := make(chan struct{})
chStop := make(chan struct{})
go func(){
time.Sleep(time.Second * 1)
chPrint <- struct{}{}
time.Sleep(time.Second * 1)
chPrint <- struct{}{}
time.Sleep(time.Second * 1)
chStop <- struct{}{}
}()
var sum int
for {
time.Sleep(time.Millisecond)
select {
case <-chPrint:
fmt.Println("for+select now is", sum)
case <-chStop:
fmt.Println("for+select stop, result is", sum)
return
default:
if sum == 10000 {
fmt.Println("for+select end, result is", sum)
return
}
sum += 1
}
}
}
for+select now is 766
for+select now is 1540
for+select stop, result is 2309
Определить, закрыта ли труба
func t6() {
ch := make(chan struct{})
go func() {
close(ch)
//ch <- struct{}{} // 只运行这句, 输出OK
}()
if _, ok := <-ch; ok {
fmt.Println("if channel is ok")
return
}
fmt.Println("if channel is bad")
}
if channel is bad
Используйте только отправку или только получение в качестве параметра передачи, и то же самое может быть и возвращаемым значением.
func t7() {
ch := make(chan struct{})
chExit := make(chan struct{})
go func(chRecv <-chan struct{}) {
fmt.Println("recv channel")
<-chRecv
chExit<- struct{}{}
}(ch)
go func(chSend chan<- struct{}) {
fmt.Println("send channel")
chSend <- struct{}{}
}(ch)
<-chExit
}
send channel
recv channel
Краткое изложение процесса механизма канала
makechan()
инициализацияhchan
структура, выделенная, если нет буфераhchanSize
Размер памяти и возврат; а в случае буфера вычисляется и распределяется размер типа элемента канала.hchanSize
+(elem.size
* size
) размер памяти (буфер имеет кольцевую структуру) и, наконец, возвращаетhchan
.
chansend()
В направленииchannel
Чтобы отправить данные, сначала заблокируйте текущую сопрограмму.Существуют следующие ситуации, которые оцениваются по порядку:
- Если есть ожидающий получатель, немедленно перенаправьте его получателю, снимите блокировку и выйдите.
- Когда буфер доступен, переместите значение в целевой буфер, чтобы дождаться его получения, снять блокировку и выйти.
- Выйдите, если он не блокирует (для выбора), снимите блокировку и выйдите.
- Заблокируйте текущую сопрограмму, поместите текущую сопрограмму в очередь ожидания отправки и снимите блокировку, а также очистите sudog после пробуждения.
chanrecv()
перениматьchannel
По данным , сначала блокируем текущую сопрограмму, бывают следующие ситуации, судите по порядку:
-
channel
Закрыть и данные не буферизуются, значение, полученное получателем, будет равно нулю, снять блокировку и выйти. - Когда в очереди отправки есть отправитель, он немедленно получает данные, снимает блокировку и выходит.
- Если есть буферизованные данные, скопируйте данные в приемник, снимите блокировку и выйдите.
- Выйдите, если он не блокирует (для выбора), снимите блокировку и выйдите.
- Заблокируйте текущую сопрограмму, поместите текущую сопрограмму в очередь ожидания отправки и снимите блокировку, а также очистите sudog после пробуждения.
и
chansend
Почти, есть еще одно мнение, что он закрыт и не имеет буферизованных данных.
closechan
закрытиеchannel
, сначала также получите блокировку, закройте канал и освободите все очереди приема и отправки и разбудите все sudogs.
Но данные в буфере не будут очищаться, ожидая получения в любое время.