channel 简介
goroutine 是 Go 中实现并发的重要机制,channel 是 goroutine 之间进行通信的重要桥梁。channel 是一种go协程用以接收或发送消息的安全的消息队列,channel 就像两个go协程之间的导管,来实现各种资源的同步。

声名创建 channel 常用两种方式,
//方式1:使用make创建(必须定义其传递的数据类型)
ch :make(chan int, 2) //创建缓冲通道
ch :make(chan int) //创建非缓冲通道
ch :make(chan string, 0) //创建非缓冲通道
//方式2:直接使用var声明
var ch chan int
缓冲channel与非缓冲channel
缓冲channel:拥有缓冲区,当缓冲区已满时,发送者会堵塞;当缓冲区为空时,接收者会堵塞。
简单使用例子,如下
func main() {
ch := make(chan int, 1) // 创建一个类型为int,缓冲区大小为1的channel
ch <- 2 // 将2发送到ch
n, ok := <- ch // n接收从ch发出的值
if ok {
fmt.Println(n) // 输出:2
}
close(ch) // 关闭channel
}
使用 channel 的注意点:
- 向一个已经 close 掉的 channel 发送消息,会触发 panic;
- 不能向关闭后的 channel 发送消息,但可以继续 channel 接收消息;
- 向一个 nil 的 channel 发送消息,会一直堵塞;
- 当 channel 已关闭且 channel缓存区为空时,继续从 channel 接收消息会得到一个对应类型的零值。
非缓冲channel:是指缓冲区大小为0的channel,这种channel的接收者会阻塞直至接收到消息,发送者会阻塞直至接收者接收到消息,这种机制可以用于两个goroutine进行状态同步。
简单例子:main 函数中起了一个 goroutine,通过非缓冲队列的使用,能够保证在 goroutine 执行结束之前 main 函数不会提前退出,如下:
func worker(done chan bool){
fmt.Println("start working...")
done <- true
fmt.Println("end working...")
}
func main() {
done := make(chan bool, 1)
go worker(done)
<- done
}
select 简介
select 专门用于通道发送和接收操作,看起来和 switch 很相似,但是进行选择和判断的方法完全不同。
在下述例子中,通过 select 的使用,保证了 worker 中的事务可以执行完毕后才退出 main 函数
func strWorker(ch chan string) {
time.Sleep(1 * time.Second)
fmt.Println("do something with strWorker...")
ch <- "str"
}
func intWorker(ch chan int) {
time.Sleep(2 * time.Second)
fmt.Println("do something with intWorker...")
ch <- 1
}
func main() {
chStr := make(chan string)
chInt := make(chan int)
go strWorker(chStr)
go intWorker(chInt)
for i := 0; i < 2; i++ {
select {
case <-chStr:
fmt.Println("get value from strWorker")
case <-chInt:
fmt.Println("get value from intWorker")
}
}
}
1576

被折叠的 条评论
为什么被折叠?



