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循环包起来