最近一直又被问到chan 的阻塞和非阻塞模式有什么区别,他们分别在什么场景下使用,写个日记记录下
阻塞模式
示例代码
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
ch <- 1
time.Sleep(3 * time.Second)
i := <-ch
fmt.Println(i)
}
很明显以上代码会报错fatal error: all goroutines are asleep - deadlock!
,非阻塞channel同一时刻必须有读端(i=:<-ch)和写端(ch <- 1),可以理解为一个同步过程,所以有的地方把他叫做同步通道, 修改代码如下就可以正常运行.
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
go func() {
ch <- 1
time.Sleep(3 * time.Second)
}()
i := <-ch
fmt.Println(i)
}
应用场景:阻塞主程序,如果能捕获系统Interrupt
信号,则退出主程序,执行清理工作, 示例代码如下
func Consumer() {
// do something
stop := make(chan os.Signal)
signal.Notify(stop, os.Interrupt)
<-stop
endProcess()
}
func endProcess() {
fmt.Println("我来结束程序")
time.Sleep(3 * time.Second)
}
如果使用select 程序永远都不会报fatal error: all goroutines are asleep - deadlock!
如下所示
package main
import (
"fmt"
"time"
)
func main() {
messages := make(chan string)
signals := make(chan bool)
select {
case msg := <-messages:
fmt.Println("received message", msg)
default:
fmt.Println("no message received")
}
go func() { messages <- "hi" }()
time.Sleep(1 * time.Second)
select {
case msg := <-messages:
fmt.Println("received message", msg)
case sig := <-signals:
fmt.Println("received signal", sig)
default:
fmt.Println("no activity")
}
}
明天争取把非阻塞的通道补上。