Go的并发没有它,就像iphone没有网络一样

共 795字,需浏览 2分钟

 ·

2022-06-02 11:58

点击上方“Go语言进阶学习”,进行关注

回复“Go语言”即可获赠从入门到进阶共10本电子书

鸿雁几时到,江湖秋水多。

Go的并发没有它,就像iphone没有网络一样


“ 阅读本文大概需要4.6分钟 ”

简介

    Golang的并发属性是该语言的一个大杀器,说到并发就不能不提Channel,你可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯。这篇文章来深入了解一下 channel

channel 的设计是基于 CSP 模型的。CSP 是 Communicating Sequential Process 的简称,中文可以叫做通信顺序进程,是一种并发编程模型,由 Tony Hoare 于 1977 年提出。简单来说,CSP 模型由并发执行的实体(线程或者进程)所组成,实体之间通过发送消息进行通信,这里发送消息时使用的就是通道,或者叫 channel。CSP 模型的关键是关注 channel,而不关注发送消息的实体。Go 语言实现了 CSP 部分理论,goroutine 对应 CSP 中并发执行的实体,channel 也就对应着 CSP 中的 channel。

创建Channel

  • Go中的Channel使用chan作为关键字。

  • 无缓冲chan情况下,发送和接收会一直阻塞着,直到另一方准备好。这种方式可以用来在gororutine中进行同步,- 而需要使用锁或者条件变量。

  • 有缓冲chan,可以尽量避免阻塞,提高应用的性能,典型的以时间换空间。

aChan := make(chan int)  // 创建无缓冲chan
bChan := make(chan int, N) // 创建缓冲为N的chan

赋值和取值

    从以下代码中看不出它的巨大作用,很正常,那是因为他们两条语句通常不在一起,例如:协程A发送数据,协程B接收数据

mchan <- value  // 发送值v到Channel ch中
value := <-mchan // 从Channel ch中接收数据,并将数据赋值给v

Select

    Selsect是获取Channel中数据的最常用方式。

select 一定程度上可以类比于 linux 中的 IO 多路复用中的 select。后者相当于提供了对多个 IO 事件的统一管理,而 Golang 中的 select 相当于提供了对多个 channel 的统一管理。当然这只是 select 在 channel 上的一种使用方法。

func main(){
   ch1 := make(chan int, 1)
   ch2 := make(chan int, 1)

   select {
       case e1 := <-ch1:
       //如果ch1通道成功读取数据,则执行该case处理语句
           fmt.Printf("1th case is selected. e1=%v",e1)
       case e2 := <-ch2:
       //如果ch2通道成功读取数据,则执行该case处理语句
           fmt.Printf("2th case is selected. e2=%v",e2)
       default:
       //如果上面case都没有成功,则进入default处理流程
           fmt.Println("default!.")
   }
}

for…range

    for …… range语句可以处理Channel。

    go func() {
       time.Sleep(1 * time.Hour)
   }()
   c := make(chan int)
   go func() {
       for i := 0; i < 10; i = i + 1 {
           c <- i
       }
       close(c)
   }()
   for i := range c {
       fmt.Println(i)
   }
   fmt.Println("Finished")

timeout

    Select很重要的一个应用就是超时处理。因为上面提供的demo,select语句就会一直阻塞着。这时候我们可能就需要一个超时操作,用来处理超时的情况。下面这个例子我们会在2秒后往channel c1中发送一个数据,但是Select设置为1秒超时,因此我们会打印出timeout 1,而不是result 1。

    c1 := make(chan string, 1)
   go func() {
       time.Sleep(time.Second * 2)
       c1 <- "result 1"
   }()
   select {
   case res := <-c1:
       fmt.Println(res)
   case <-time.After(time.Second * 1):
       fmt.Println("timeout 1")
   }

close

    Go内建的close方法就可以用来关闭channel。但如果channel 已经被关闭,继续往它发送数据会导致panic: send on closed channel:

 close(mChan)

------------------- End -------------------

往期精彩文章推荐:

欢迎大家点赞,留言,转发,转载,感谢大家的相伴与支持

想加入Go学习群请在后台回复【入群

万水千山总是情,点个【在看】行不行

浏览 36
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报