1、任务编排

1、有一道经典的使用 Channel 进行任务编排的题,你可以尝试做一下:有四个 goroutine,编号为 1、2、3、4。每秒钟会有一个 goroutine 打印出它自己的编号,要求你编写一个程序,让输出的编号总是按照 1、2、3、4、1、2、3、4、……的顺序打印出来。

  • 双向通道可以赋值给单向通道,但是单向通道不能赋值给双向通道,不同方向的单向通道也不能互相赋值
  • select {} 会阻塞主协程等待子协程

image.png

  1. // 解法1
  2. package main
  3. import (
  4. "fmt"
  5. "time"
  6. )
  7. func main() {
  8. ch := make(chan int, 4)
  9. for {
  10. for i := 1; i < 5; i++ {
  11. ch <- i
  12. go func() {
  13. st := <-ch
  14. fmt.Println(st)
  15. }()
  16. time.Sleep(1 * time.Second)
  17. }
  18. }
  19. }
  20. // 解法2
  21. package main
  22. import (
  23. "fmt"
  24. "sync"
  25. "time"
  26. )
  27. var (
  28. c1 = make(chan int, 1)
  29. c2 = make(chan int, 1)
  30. c3 = make(chan int, 1)
  31. c4 = make(chan int, 1)
  32. )
  33. func main() {
  34. var wg sync.WaitGroup
  35. wg.Add(4)
  36. c4 <- 1
  37. go func() { //1
  38. for {
  39. time.Sleep(time.Second)
  40. <-c4
  41. fmt.Print(1, " ")
  42. c1 <- 1
  43. }
  44. wg.Done()
  45. }()
  46. go func() { //2
  47. for {
  48. time.Sleep(time.Second)
  49. <-c1
  50. fmt.Print(2, " ")
  51. c2 <- 2
  52. }
  53. wg.Done()
  54. }()
  55. go func() { //3
  56. for {
  57. time.Sleep(time.Second)
  58. <-c2
  59. fmt.Print(3, " ")
  60. c3 <- 3
  61. }
  62. wg.Done()
  63. }()
  64. go func() { //4
  65. for {
  66. time.Sleep(time.Second)
  67. <-c3
  68. fmt.Print(4, " ")
  69. c4 <- 4
  70. }
  71. wg.Done()
  72. }()
  73. wg.Wait()
  74. }
  75. // 解法3
  76. package main
  77. import (
  78. "fmt"
  79. "time"
  80. )
  81. func main() {
  82. chArr := [4]chan struct{}{
  83. make(chan struct{}),
  84. make(chan struct{}),
  85. make(chan struct{}),
  86. make(chan struct{}),
  87. }
  88. for i := 0; i < 4; i++ {
  89. go func(i int) {
  90. for {
  91. <-chArr[i%4]
  92. fmt.Printf("i am %d\n", i)
  93. time.Sleep(1 * time.Second)
  94. chArr[(i+1)%4] <- struct{}{}
  95. }
  96. }(i)
  97. }
  98. chArr[0] <- struct{}{}
  99. select {}
  100. }