Go: select、case的运用

下面的例子很好的反映了select、case、协程的运作,实现的功能是:随机打印1或者2,到达超时后停止。

实现方法:

1个协程设置超时状态,主协程执行随机打印(随机可以用"math/rand"包实现,这里只是为了学习select、case)。
定义1个超时状态chan,标记超时状态。

无缓冲的channel:

1-写入堵塞,直到其他协程读取;
2-读取堵塞,直到其他协程写入。
定义1个1个缓冲chan,使用select、case实现随机读写。

带缓冲的channel:

1-写满后再写堵塞,直到被其他协程读取;
2-为空时去读堵塞,直到被其他协程写入;
3-未写满情况下可一直写入;
4-未空情况下可一直读,读一个少一个,先进先出;
5-只要不触发满后写,空后读,可以实现针对此channel的无堵塞不限读写使用。这个例子就是用了这个处理。
select、case针对channel的I/O进行判断,成功读取或写入就执行对应代码段,都失败就执行default对应代码段

package main
import (
   "fmt"
   "time"
)
func testSelectBase() {
   fmt.Println("select-case语句针对io起作用,写入、读取信道满足其中一个条件就可执行继续")
   i := make(chan int, 1) //定义个1个缓冲的channel,这样写入第2个值时才会堵塞,使用无缓冲的话会直接死锁
   timeout := make(chan bool)
   go func() { //设置一个超时限制下面的循环
      time.Sleep(10 * time.Second)
      timeout <- true
   }()
   fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "运行开始")//这个是go显示yyyy-mm-dd HH:MM:SS格式的语法,奇葩!据说是go发布时间...
loop:
   for {
      select {
      case <-timeout:  //尝试读取timeout
         break loop
      default: //因为设置超时的协程需要等超时到后才给timeout写入,所以在此之前一直执行下面代码段
         select { //随机执行写入i
         case i <- 1: //成功就执行
            fmt.Printf("写入了1\t")
         case i <- 2: //成功就执行
            fmt.Printf("写入了2\t")
         }
         fmt.Printf("获取i的值是%d\n", <-i) //读取i的值
         time.Sleep(500 * time.Millisecond)
      }
   }
   fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "运行完毕")
}
func main() {
   testSelectBase()
}

你可能感兴趣的:(Go: select、case的运用)