select...case的使用

package main

import (
   "fmt"
   "time"
)

func main() {
   intChan1 := make(chan int)
   intChan2 := make(chan int)
   intChan3 := make(chan int)

   // 协程1
   go func() {
      for i1 := 0; i1 < 5; i1++ {
         intChan1 <- i1 // 向管道写入数据
         time.Sleep(time.Second)
         <-intChan1 // 从管道读出数据
      }
   }()

   // 协程2
   go func() {
      for i2 := 0; i2 < 5; i2++ {
         intChan2 <- i2 // 向管道写入数据
         time.Sleep(time.Second)
         <-intChan2 // 从管道读出数据
      }
   }()

   // 协程3
   go func() {
      for i3 := 0; i3 < 5; i3++ {
         intChan3 <- i3 // 向管道写入数据
         time.Sleep(time.Second)
         <-intChan3 // 从管道读出数据
      }
   }()

   // 适用死循环监控管道的读写情况
   for {
      select {
      // 监控三个管道的写入情况
      case i, ok := <-intChan1:
         if ok {
            fmt.Printf("监控到『管道1』写入了数据『%+v\n", i)
         } else {
            fmt.Printf("『管道1』已关闭\n")
         }
      case i, ok := <-intChan2:
         if ok {
            fmt.Printf("监控到『管道2』写入了数据『%+v\n", i)
         } else {
            fmt.Printf("『管道2』已关闭\n")
         }
      case i, ok := <-intChan3:
         if ok {
            fmt.Printf("监控到『管道3』写入了数据『%+v\n", i)
         } else {
            fmt.Printf("『管道3』已关闭\n")
         }

      // 监控三个管道的读取情况
      case intChan1 <- 0:
         fmt.Printf("监控到『管道1』读出了数据 \n")
      case intChan2 <- 0:
         fmt.Printf("监控到『管道2』读出了数据 \n")
      case intChan3 <- 0:
         fmt.Printf("监控到『管道3』读出了数据 \n")

      // 强烈建议设置default,避免出现deadlock,哪怕default里不做任何操作
      default:
      }
   }
}

//========== 输出过程·开始 ==========//
// 监控到『管道1』写入了数据『0』
// 监控到『管道2』写入了数据『0』
// 监控到『管道3』写入了数据『0』
// 监控到『管道2』读出了数据
// 监控到『管道1』读出了数据
// 监控到『管道2』写入了数据『1』
// 监控到『管道1』写入了数据『1』
// 监控到『管道3』读出了数据
// 监控到『管道3』写入了数据『1』
// 监控到『管道1』读出了数据
// 监控到『管道2』读出了数据
// 监控到『管道1』写入了数据『2』
// 监控到『管道2』写入了数据『2』
// 监控到『管道3』读出了数据
// 监控到『管道3』写入了数据『2』
// 监控到『管道2』读出了数据
// 监控到『管道1』读出了数据
// 监控到『管道2』写入了数据『3』
// 监控到『管道3』读出了数据
// 监控到『管道1』写入了数据『3』
// 监控到『管道3』写入了数据『3』
// 监控到『管道1』读出了数据
// 监控到『管道2』读出了数据
// 监控到『管道1』写入了数据『4』
// 监控到『管道2』写入了数据『4』
// 监控到『管道3』读出了数据
// 监控到『管道3』写入了数据『4』
// 监控到『管道1』读出了数据
// 监控到『管道2』读出了数据
// 监控到『管道3』读出了数据
// ▎(阻塞中)
//========== 输出过程·开始 ==========//

//========== 总结 ==========//
// 1、select...case和switch...case在形式上非常像,select主要使用场景就是监听管道的读写,可以说是管道版的switch。
// 2、select里的case是随机执行的,而不像switch里的case是顺序执行的,若匹配到多个case只会随机执行其中一个,其余的不会执行。
// 3、如果没有匹配到case且没有设置default就会发生阻塞,直到有可以匹配的case,所以强烈建议设置default,避免出现阻塞。

Copyright © 2024 码农人生. All Rights Reserved