首页 > 代码库 > Go之go与channel组合使用

Go之go与channel组合使用

1,等待一个事件
1,等待一个事件(Event)

这里的第17行<-ch 将一直阻塞,直到ch被关闭 或者 ch中可以取出值 为止
所以到第17行之后会去执行go后面的func()匿名函数,在里面给ch赋值后(或者close(ch))后,才能继续往后执行

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. fmt.Println("Begin doing something!")
  7. ch := make(chan int)
  8. go func() {
  9. fmt.Println("Doing something…")
  10. ch <- 22
  11. //close(ch)
  12. }()
  13. <-ch //此处将被阻塞,直到ch被关闭 或 有值可以取出
  14. fmt.Println("Done!")
  15. }

2,协同多个Goroutines
同上,close channel还可以用于协同多个Goroutines,比如下面这个例子,我们创建了100个Worker Goroutine,这些Goroutine在被创建出来后都阻塞在"<-start"上,直到我们在main goroutine中给出开工的信号:"close(start)",这些goroutines才开始真正的并发运行起来。
  1. package main
  2. import "fmt"
  3. func worker(start chan bool, index int) {
  4. <-start // 从start中取出数据后,调用20行的case语句
  5. fmt.Println("This is Worker:", index)
  6. }
  7. func main() {
  8. start := make(chan bool)
  9. for i := 1; i <= 10; i++ {
  10. go worker(start, i)
  11. }
  12. //给start赋值10次,让worker方法执行10次
  13. for i := 1; i <= 10; i++ {
  14. start <- true //给start赋值一次,便执行worker函数一次
  15. }
  16. v := 1
  17. //select 被一直阻塞直到start中数据被取出
  18. select {  //deadlock we expected
  19. case <-start:
  20. fmt.Print(v)
  21. v++
  22. }
  23. }
3,Select
  • select常与for一起使用
  1. for {
  2. select {
  3. case x := <- somechan:
  4. // … 使用x进行一些操作
  5. case y, ok := <- someOtherchan:
  6. // … 使用y进行一些操作,
  7. // 检查ok值判断someOtherchan是否已经关闭
  8. case outputChan <- z:
  9. // … z值被成功发送到Channel上时
  10. default:
  11. // … 上面case均无法通信时,执行此分支
  12. }
  13. }
  • 终结woker

下面是一个常见的终结sub worker goroutines的方法,
每个worker goroutine通过select监视一个die channel来及时获取main goroutine的退出通知。
  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func worker(die chan bool, index int) {
  7. fmt.Println("Begin: This is Worker:", index)
  8. for {
  9. select {
  10. //case xx:
  11. //做事的分支
  12. case <-die: //到这里就被阻塞,运行main中的close后输出 done
  13. fmt.Println("Done: This is Worker:", index)
  14. return
  15. }
  16. }
  17. }
  18. func main() {
  19. die := make(chan bool)
  20. for i := 1; i <= 10; i++ {
  21. go worker(die, i)
  22. }
  23. time.Sleep(time.Second * 5)
  24. close(die)
  25. select {} //deadlock we expected
  26. }

  • 终结验证
有时候终结一个worker后,main goroutine想确认worker routine是否真正退出了,可采用下面这种方法:
  1. package main
  2. import (
  3. "fmt"
  4. //"time"
  5. )
  6. func worker(die chan bool) {
  7. fmt.Println("Begin: This is Worker")
  8. for {
  9. select {
  10. //case xx:
  11. //做事的分支
  12. case <-die: //这里等待27行的赋值语句,如果没有赋值,一直阻塞
  13. fmt.Println("Done: This is Worker")
  14. die <- true
  15. return
  16. }
  17. }
  18. }
  19. func main() {
  20. die := make(chan bool)
  21. go worker(die)
  22. die <- true
  23. istrue := <-die //这里等待16行的赋值,赋值完毕后程序继续执行
  24. fmt.Println("Worker goroutine has been terminated", istrue)
  25. }
  • 关闭的Channel永远不会阻塞


来自为知笔记(Wiz)


Go之go与channel组合使用