通道接收同样使用<-操作符
通道接收有如下特性
① 通道的收发操作在不同的两个 goroutine 间进行。
由于通道的数据在没有接收方处理时,数据发送方会持续阻塞,因此通道的接收必定在另外一个 goroutine 中进行。
② 接收将持续阻塞直到发送方发送数据。
如果接收方接收时,通道中没有发送方发送数据,接收方也会发生阻塞,直到发送方发送数据为止。
③ 每次接收一个元素。
通道一次只能接收一个数据元素。
阻塞模式接收数据时,将接收变量作为<-操作符的左值,格式如下:
data := <-ch
执行该语句时将会阻塞,直到接收到数据并赋值给 data 变量。
使用非阻塞方式从通道接收数据时,语句不会发生阻塞,格式如下:
data, ok := <-ch
data:表示接收到的数据。未接收到数据时,data 为通道类型的零值。
ok:表示是否接收到数据。
非阻塞的通道接收方法可能造成高的 CPU 占用,因此使用非常少。如果需要实现接收超时检测,可以配合 select 和计时器 channel 进行,可以参见后面的内容。
阻塞接收数据后,忽略从通道返回的数据,格式如下:
<-ch
执行该语句时将会发生阻塞,直到接收到数据,但接收到的数据会被忽略。这个方式实际上只是通过通道在 goroutine 间阻塞收发实现并发同步。
使用通道做并发同步的例子:
package main
func main() {
ch := make(chan int)
go func() {
for i := 1; i <= 10; i++ {
println(i)
}
ch <- 1
}()
println("main done")
// 利用接受产生阻塞
<-ch
}
通道的数据接收可以借用 for 语句进行多个元素的接收操作,示例代码 :
package main
import (
"time"
)
func main() {
// 创建管道
ch := make(chan int)
// 协程取值
go func() {
for {
data := <-ch
if data == -1 {
break
}
println("取出", data)
}
}()
// 向管道发送数据
for i := 1; i <= 10; i++ {
println("放入 :", i)
ch <- i
// 每次发送完时等待
time.Sleep(time.Second)
}
// 通知读取协程退出
ch <- -1
println("main done")
}
使用 for range 遍历管道
package main
func main() {
// 创建管道
ch := make(chan int)
// 启动一个goroutine 向管道内写入数据
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
// close 管道
close(ch)
}()
//
for data := range ch {
println(data)
}
println("main end")
}
注意关闭管道避免锁死.