channels

默认情况下,发送和接收操作在另一端准备好之前都会阻塞。这使得 Go 程可以在没有显式的锁或竞态变量的情况下进行同步。

  1. 使用前必须被创建

    c := make(chan int)

  2. 可以指定缓冲区大小

    cc := make(chan int,2)

  1. package main
  2. import "fmt"
  3. func sum(s []int, c chan int) {
  4. sum := 0
  5. for _, v := range s {
  6. sum += v
  7. }
  8. c <- sum
  9. }
  10. func main() {
  11. s := []int{1, 2, 3, 4, 5}
  12. //使用前必须创建
  13. c := make(chan int)
  14. go sum(s[:len(s)/2], c)
  15. go sum(s[len(s)/2:], c)
  16. x, y := <-c, <-c
  17. fmt.Println(x, y, x+y) //12 3 15
  18. //使用前可以指定缓冲区大小
  19. cc := make(chan int, 5)
  20. cc <- 2
  21. cc <- 3
  22. cc <- 4
  23. fmt.Println(<-cc)
  24. fmt.Println(<-cc)
  25. fmt.Println(<-cc)
  26. // fmt.Println(<-cc) //fatal error: all goroutines are asleep - deadlock!
  27. }

close,range

close

发送者通过close(c)来关闭信道
而接收者通过

v, ok := <-ch

接收表达式分配的第二个参数来判断是否关闭,如果是false,那么就关闭

  1. package main
  2. import "fmt"
  3. func fibonacci(n int, c chan int) {
  4. x, y := 0, 1
  5. for i := 0; i < n; i++ {
  6. c <- x
  7. x, y = y, x+y
  8. }
  9. close(c)
  10. // c <- x //panic: send on closed channel
  11. }
  12. func main() {
  13. c := make(chan int, 10)
  14. go fibonacci(cap(c), c)
  15. for i := range c {
  16. fmt.Println(i)
  17. }
  18. }

range

循环 for i := range c 会不断从信道接收值,直到它被关闭。
信道与文件不同,通常情况下无需关闭它们。只有在必须告诉接收者不再有需要发送的值时才有必要关闭,例如终止一个 range 循环
去掉上面程序里的close(c)会输出

0 1 …(中间是斐波拉契数列) 34 fatal error: all goroutines are asleep - deadlock!