go深入解析channel
常见问题
往未初始化的Channel写数据,会发生什么?
nil channel会永远阻塞对该channel的读写操作
1
2
3
4func main() {
var cc chan int
cc <- 1
}运行后,报错:
1
2
3fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send (nil chan)]:
main.main()上面的意思是,在main goroutine线,期望从管道中获得一个数据,而这个数据必须是其他goroutine线放入管道的,但是其他goroutine线都已经执行完了(all goroutines are asleep),那么就永远不会有数据放入管道。所以,main goroutine线在等一个永远不会来的数据,那整个程序就永远等下去了。这显然是没有结果的,所以这个程序就说“算了吧,不坚持了,我自己自杀掉,报一个错给代码作者,我被deadlock了”
channel实现等待一段时间超时后,再退出?
time.After定义
1
2
3
4
5
6
7
8
9// After waits for the duration to elapse and then sends the current time
// on the returned channel.
// It is equivalent to NewTimer(d).C.
// The underlying Timer is not recovered by the garbage collector
// until the timer fires. If efficiency is a concern, use NewTimer
// instead and call Timer.Stop if the timer is no longer needed.
func After(d Duration) <-chan Time {
return NewTimer(d).C
}select + time.After实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18func main() {
c1 := make(chan int)
c2 := make(chan int)
fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
go func() {
time.Sleep(time.Duration(2 * time.Second))
fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
c1 <- 2
}()
select {
case n := <-c1:
fmt.Println("receive from c1: ", n)
case n := <-c2:
fmt.Println("receive from c2: ", n)
case <-time.After(8 * time.Second):
fmt.Println("timeout,no receive")
}
}select + for实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19func main() {
stop := make(chan bool)
go func() {
for {
select {
case <-stop:
// 收到stop channel,结束goroutine
return
default:
// 不做处理,等待stop channel
time.Sleep(2 * time.Second)
}
}
}()
time.Sleep(10 * time.Second)
// 停止goroutine
stop <- true
time.Sleep(5 * time.Second)
}
特性介绍
channel主要用于多个goroutine通讯,其内部实现了同步,确保并发安全,默认为同步模式。
同步方式需要发送和接受配对。否则会被阻塞,直到另一方准备好后被唤醒。
异步方式通过判断缓冲区来决定是否阻塞,如果缓冲区已满,则发送被阻塞;缓冲区为空,则接收被阻塞
实现原理
channel都是以hchan结构体形式存在,
1 |
|
Reference
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!