用go撸一个生产者消费型,用channel通信,怎么友好的关闭chan?

参考解析

题目来源: 七牛云、字节跳动

答案:

如何优雅的关闭channel 记住两点

  1. 向一个已关闭的channel发送数据会panic
  2. 关闭一个已经关闭的channel会panic

针对单个生产者 在发送侧关闭channel即可

单个生产者单个消费者模型

  1. func main() {
  2. var ch = make(chan int)
  3. // 单生产者
  4. go func() {
  5. for i := 1; i < 100; i++ {
  6. ch <- i
  7. }
  8. close(ch)
  9. }()
  10. // 消费者
  11. go func() {
  12. for elem := range ch {
  13. fmt.Println(elem)
  14. }
  15. }()
  16. select {}
  17. }

单个生产者多个消费者模型

  1. func main() {
  2. var ch = make(chan int)
  3. // 单生产者
  4. go func() {
  5. for i := 1; i < 100; i++ {
  6. ch <- i
  7. }
  8. close(ch)
  9. }()
  10. // 多消费者
  11. for i := 0; i < 100; i++ {
  12. go func() {
  13. for elem := range ch {
  14. fmt.Println(elem)
  15. }
  16. }()
  17. }
  18. select {}
  19. }

针对多个生产者 不应该关闭生产者,消费者通知生产者不发送数据即可

多生产者单消费者模型

  1. func main() {
  2. var ch = make(chan int)
  3. var stopCh = make(chan struct{})
  4. // 多生产者
  5. for i := 1; i <= 100; i++ {
  6. go func(n int) {
  7. for {
  8. select {
  9. case ch <- n:
  10. case <-stopCh:
  11. return
  12. }
  13. }
  14. }(i)
  15. }
  16. // 单消费者
  17. go func() {
  18. for elem := range ch {
  19. fmt.Println(elem)
  20. if elem == 100{
  21. return
  22. }
  23. }
  24. }()
  25. select {}
  26. }

多生产者多消费者模型

  1. func main() {
  2. var ch = make(chan int)
  3. // 停止信号
  4. var stopCh = make(chan struct{})
  5. // 协调者
  6. var toStopCh = make(chan struct{}, 1)
  7. // 多生产者
  8. for i := 1; i <= 100; i++ {
  9. go func(n int) {
  10. for {
  11. select {
  12. case ch <- n:
  13. case <-stopCh:
  14. return
  15. }
  16. }
  17. }(i)
  18. }
  19. // 接收通知给协调者
  20. go func() {
  21. <-toStopCh
  22. close(stopCh)
  23. }()
  24. // 多消费者
  25. for i := 0; i < 100; i++ {
  26. go func() {
  27. for {
  28. select {
  29. case elem := <-ch:
  30. if elem == 100 {
  31. toStopCh <- struct{}{}
  32. return
  33. }
  34. fmt.Println(elem)
  35. }
  36. }
  37. }()
  38. }
  39. select {}
  40. }