其他分享
首页 > 其他分享> > Go channel简介

Go channel简介

作者:互联网

channel

用于在并发单元之间通信,类似于管道

ch := make(chan int)	// 创建一个channel
defer close(ch)
ch <- v					// 向管道中写入
v := <-ch				// 从管道读取
v, ok := <-ch

channel有三种类型[可读可写 | 只读 | 只写]

chan T		// rw
chan<- T	// w
<-chan T	// r

如果在创建一个channel的时候指定了容量,则这个chan就是非阻塞的;否则是阻塞的(并且如果检测到主程序有【读/写】,并发程序里没有【写/读】,或者缓冲区满了,就会报deadlock)

阻塞式或者缓存满状态下的非阻塞式的读写都会被block

ch1 := make(chan int) //阻塞式
ch2 := make(chan int, 10) //非阻塞,缓冲区为10

// deadlock
ch1 <- 1
// deadlock
for i:=0;i<=10;i++{
    ch2 <- i
}
// 正常
go func(){
    ch1 <- 1
}
i := <-ch1
// 正常
go func(){
    i := <-ch1
}
ch1 <- 1
// 正常
ch2 <- 1
v := <-ch2

在向管道写入之前,会将表达式的值计算出来

如果往已经close的channel中写,会报panic;如果是读,则会立即返回该类型的零值,可以用ok字段来检查

// ch <- 7
ch <- (3+4)

close(ch)

// panic
ch <- 1

// 检查
v, ok := <- ch

利用chan的阻塞机制,可以用于

  1. 等待协程执行完成
func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s{
        sum += v
    }
    c <- sum
}

func main(){
    s := []int{1, 2, 3, 4, 5}
    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)
    // 用于等待协程执行完成
    x, y := <-c, <-c
    // 或者这样写
    for half := range c{
        // half先后得到x和y
        // 一直等待到c被关闭
    }
}
  1. 实现协程中的同步操作(这里读写有点类似于进程同步里的PV操作)

比如下面的例子,worker在执行完成之后,通过done通知主协程继续执行

func worker(done chan bool){
    time.Sleep(time.Second)
    done <- true
}

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

比较类似于switch,就是每个case是一个跟管道相关的操作,select会从当前能够执行的case中随机选择一个执行

如果所有case都不能执行,就会执行default

如果default不存在,就会阻塞,或者用time.After自行定义超时操作

select {
    case c <- x:
    	x, y = y, x+y
    case <-quit:
    	fmt.Println("quit")
    	return
    case <-time.After(time.Second * 1):
    	fmt.Println("timeout")
}

Timer是一个定时器,可以指定一段之间之后执行,通过chan完成

timer := time.NewTimer(time.Second * 2)
go func(){
    <-timer.C
    ...
}
// 可以用stop停止
stop := timer.Stop()
if stop {
    ...
}

Ticker是一个定时触发的计时器,可以指定每隔一段时间执行一次,也是通过chan来完成的

ticker := time.NewTicker(time.Millisecond * 500)
go func (){
    for t := range ticker.C {
        fmt.Println("tick at ", t)
    }
}()
// 可以用stop停止
stop := ticker.Stop()
if stop {
    ...
}

Go Channel 详解

标签:int,简介,chan,阻塞,go,time,Go,channel
来源: https://blog.csdn.net/weixin_45698935/article/details/123596419