goroutine和chan配合是golang的核心技术, 必须深入研究一下使用方法.
无缓冲chan
进和出都会阻塞.
例1:
func main() {
ch := make(chan error)
fmt.Println("main1")
go func() {
fmt.Println("go1")
ch <- nil //阻塞
fmt.Println("go2") //永远不会执行
}()
fmt.Println("main2")
time.Sleep(1 * time.Second)
fmt.Println("main等待1秒")
fmt.Println("main3")
}
输出:
main1
main2
go1
main等待1秒
main3
例2:
func main() {
ch := make(chan error)
fmt.Println("main1")
go func() {
fmt.Println("go1")
fmt.Println("go等待1秒")
time.Sleep(1 * time.Second)
ch <- nil //阻塞等待
fmt.Println("go2")
}()
fmt.Println("main2")
fmt.Println("main等待1秒")
time.Sleep(1 * time.Second)
<-ch //阻塞等待
fmt.Println("main3")
time.Sleep(2 * time.Second)
}
输出:
main1
main2
main等待1秒
go1
go等待1秒
main3
go2
有缓冲chan
先进先出队列, 出会一直阻塞到有数据, 进时当队列未满不会阻塞, 队列已满则阻塞.
select
- select 先遍历所有case, 所有channel表达式都会被求值、所有被发送的表达式都会被求值。求值顺序:自上而下、从左到右.
- 当case没有阻塞则执行一个没有阻塞的case就退出select
- 当所有case阻塞时, 则一直阻塞直到某个case解除阻塞, 但是如果有default则直接执行default
- 也就是一个select最多里的代码
- 要一直检测case则必须外层使用for循环包起来