go channel && select

channel 简介

goroutine 是 Go 中实现并发的重要机制,channel 是 goroutine 之间进行通信的重要桥梁。channel 是一种go协程用以接收或发送消息的安全的消息队列,channel 就像两个go协程之间的导管,来实现各种资源的同步。
go channel && select_第1张图片
声名创建 channel 常用两种方式,

//方式1:使用make创建(必须定义其传递的数据类型)
ch :make(chan int, 2)  //创建缓冲通道
ch :make(chan int)  //创建非缓冲通道
ch :make(chan string, 0)  //创建非缓冲通道



//方式2:直接使用var声明
var ch chan int

缓冲channel与非缓冲channel

缓冲channel:拥有缓冲区,当缓冲区已满时,发送者会堵塞;当缓冲区为空时,接收者会堵塞。

简单使用例子,如下

func main() {    
	ch := make(chan int, 1) // 创建一个类型为int,缓冲区大小为1的channel    
	ch <- 2 // 将2发送到ch    
	n, ok := <- ch // n接收从ch发出的值    
	if ok {        
		fmt.Println(n) // 输出:2    
	}    
	close(ch) // 关闭channel
}

使用 channel 的注意点:

  • 向一个已经 close 掉channel 发送消息,会触发 panic
  • 不能向关闭后的 channel 发送消息,但可以继续 channel 接收消息;
  • 向一个 nil 的 channel 发送消息,会一直堵塞;
  • channel 已关闭channel缓存区为空时,继续从 channel 接收消息会得到一个对应类型的零值。

非缓冲channel:是指缓冲区大小为0的channel,这种channel的接收者会阻塞直至接收到消息,发送者会阻塞直至接收者接收到消息,这种机制可以用于两个goroutine进行状态同步。

简单例子:main 函数中起了一个 goroutine,通过非缓冲队列的使用,能够保证在 goroutine 执行结束之前 main 函数不会提前退出,如下:

func worker(done chan bool){
    fmt.Println("start working...")
    done <- true
    fmt.Println("end working...")
}

func main() {
    done := make(chan bool, 1)
    go worker(done)
    <- done
}

select 简介

select 专门用于通道发送和接收操作,看起来和 switch 很相似,但是进行选择和判断的方法完全不同。

在下述例子中,通过 select 的使用,保证了 worker 中的事务可以执行完毕后才退出 main 函数

func strWorker(ch chan string) {
    time.Sleep(1 * time.Second)
    fmt.Println("do something with strWorker...")
    ch <- "str"
}

func intWorker(ch chan int) {
    time.Sleep(2 * time.Second)
    fmt.Println("do something with intWorker...")
    ch <- 1
}

func main() {
    chStr := make(chan string)
    chInt := make(chan int)

    go strWorker(chStr)
    go intWorker(chInt)

    for i := 0; i < 2; i++ {
        select {
        case <-chStr:
            fmt.Println("get value from strWorker")

        case <-chInt:
            fmt.Println("get value from intWorker")

        }
    }
}

你可能感兴趣的:(go,go,channel,go,select,channel,select,go通道)