ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Go channel简介

2022-03-19 16:02:38  阅读:174  来源: 互联网

标签:int 简介 chan 阻塞 go time Go channel


channel

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

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

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
}
  • select

比较类似于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和Ticker

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 {
    ...
}
  • reference

Go Channel 详解

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有