欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

go学习笔记_Routine和Channel

程序员文章站 2022-07-05 21:43:43
...

文章来源:http://www.itnose.net

go语言并发编程上

傍晚抽空学习了下go语言的并发编程,从goroutine到channel机制,从开始的稀里糊涂到现在拨开云雾见太阳的感觉,学习的过程总是令人亢奋的!当然目前的理解还是不够透彻的。下篇将举例来分析下。

goroutine

类似开辟进程、线程做法,go语言所采用的为 goroutine 。用法极其简单,也就是使用go关键字,使用方法有两种:

  • 定义一个函数functionName,要异步调用时使用语句go functionName即可。

  • 使用匿名函数,用法为go func(参数列表){函数执行体}(),说明最后一个()作用就是让该函数执行。

下面简单代码加深下:

    /////////第一种示例代码:///////////
    func sayHello(name string){
        fmt.Println("hello"+name)
    }
    //主程序入口
    func main(){
        go sayHello("PMST")
    }
    /////////第二种示例代码://////////
    //主程序入口
    func main(){
        go func(){
            fmt.Println("hello world")
        }()     //别忘记这里的()
    }

现在来讲下go关键字作用,一旦将go放在函数之前,意味分配一个子routine让这个函数自个玩去(有点自身自灭的感觉),而主 routine则继续该干嘛干嘛。打个比方,手头有一堆数据,需要经过超级复杂,超级耗时的计算才能得出答案。显然我们的主routine不可能只干这一 件事,它还有其他事情需要处理。因此,我们开辟一个routine让其自个算去。

那么问题来了,这么做确实解决了主routine不被锁死的问题,又能够完成了耗时计算,可是计算出答案之后,如何回传给主routine使用呢?

这也就是下面channel的使用了

channel

goroutine 之间如何进行数据的通信?如下两种:

  1. 共用内存内存空间。

  2. Go语言推荐的通信机制channel。

接下来是我对channel的一些理解:

  • Goroutine使用channel 接收或者发送值,而这些值只能是特定的类型,由自己指定,比如两个routine之间相互传值为int类型,那么channel类型就是chan int

  • 通过make来创建channel,例如无缓存ci := make(chan int),指定缓存cib := make(chan int,2)。很明显可以看出,区别在于后面的表述,后者表示给这个通道分类了2个缓存空间,至于区别,下文马上给出。

  • channel 通过<- 来接收和发送数据。例如 channel <- value ,显然就是把值 value 发送到通道 channel 中; value := <- ch ,注意箭头,表示从通道 channel 读取数据给 value ,或者可以说从通道channel接收数据赋值给value。顺便提及其他的写法<- channel,显然也是从通道读取数据,但是没有赋值给任何一个变量,因此表示丢弃!

关于channel的阻塞问题,我想有必要着重梳理下。请看下面的总结

首先通道的接收和发送都是阻塞的,除非与之对应的一端已经准备好。通过举例来说明是最好不过了。

  1. 新建一个通道,channel_c := make(chan int),注意是没有分配缓存的。

  2. 随后往通道写入数据,channel_c <- value,由于没有分配缓存,因此这里会被堵塞掉,换句话说就是卡死在这里,只能等待,等待程序某个地方从该通道读取数据!(ps:就好比非常短的管 子,就往里塞了一个数据,就要漏出来,因此我一直手”扶着”数据,腾不出手干下面的事了。只有当接收方来拿数据了才能腾出手来干别的事。)

  3. 2015.04.22 -> 对上面比喻修改。ps:上面比喻的不是很恰当,我想是不是可以这么认为,channel是连通两个routine的通道,当发送者向channel里发送 数据,却迟迟等不到接收者,但秉着尽职尽责的思想,始终等待在那个位置,即channel_c := make(chan int)这条发送语句处,直到接收者接收了通道数据,才可以进行下一条语句。那么假如有缓存就不同了,就好比一个驿站,拿着数据到通道这发送“邮件”,尽 管可能没有接收者,但是我却可以先暂时放到“驿站”(缓存)这里,然后继续干自己的活,等下次再向通道发送数据时发现缓存满了,就只能耐心等待,除非这时 有人来取数据,腾出缓存空间了,才可以写入数据。

  4. 现在换成从通道读取数据,v := <- channel_c,分两种情况:当channel_c通道中有数据时,那肯定不会堵塞,很顺利的读过来;当channel_c通道没有数据时,那么自然又堵死了,除非程序其它地方往通道写入数据了!

  5. 最后讲讲关于分配了缓存的通道,例如:channel := make(chan int,2)。假如这时候往通道写入数据channel <- 2,由于分配了缓存,意味着是我可以直接写入,不会堵塞了,但这仅当我的缓存区未满的情况下才不会堵塞。下面往通道写入一个channel <- 3,这是没有问题的。不过缓存已经填满了!假如这时候你再写的话就会堵塞,只有程序某个地方从改通道读取数据腾出地方了,你才可以写入!

文章来源:http://www.itnose.net/st/6252785.html
相关标签: go