学习golang(11) 初探:协程(2) 协程间通信

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,点击查看活动详情

协程基础请参考上一章,我们接着来看下协程后面的部分,协程间通信。

共享变量方式

我们协程间通信,可以采用共享变量的方式,不过得注意数据互斥,例如: 这里有一个小栗子,我们定义一个共享变量,赋初值为0,我们开启50个协程,每个协程对该值 +1,我们来看看具体效果。

我们执行程序后数据如下

为什么数据会不一样呢? 这是因为我们没有对result这个变量进行加,多个协程使用同一变量,但凡有一个协程用的是老的数据,执行结果也会修改最终值,所以才会导致这样的情况,为了避免这种情况,我们仅需对该函数加锁即可,例如: 我们将上述程序修改为如下

加入sync.Mutex ,修改程序如下

我们再次执行程序,数据如下

我们可以将上述加锁的关系简单理解为

除此之外,go sync还提供了另外一种锁sync.RWMutex,这是一种读写锁,适用于那些读多,写少。

管道方式

go中,协程间通信,很少用共享变量的方式,而更多的方式是使用管道,管道关键字chan

初探chan

我们一般使用make来申请管道,例如,我们申请一个不带缓存int类型的管道:

ch := make(chan int)
复制代码

那么管道是如何进行读写的呢? go给我提供了相关方式

我们读写管道的内容是需要使用 <- ,例如,将管道的内容赋值给变量x

x := <-ch
复制代码

例如,我们将3传入给管道ch

ch <- 3
复制代码

对于不带缓存的管道,我们在未写入之前进行读取的话,会发生等待,例如如下例子。

执行结果

通过昨天学习协程可知,主协程中开启其他协程,当主协程执行完毕后,会关闭其他协程,为了避免协程未执行完被关闭,我们了解到第一种方式是加入计算量,例如:sync.WaitGroup ,其第二种方式便是使用管道,实际例子如上。

无缓冲chan 和 有缓冲chan

上述例子介绍的便是无缓冲chan,其申请方式为make(chan int) 或则make(chan int,0) ,而我们使用make申请的时候,其size 不为0,则申请的是有缓冲chan,二者区别为

无缓冲chan,在写入之前,读取会一直等待,而有缓冲chan在使用量 < size 则不会等待,而后会一直等待,对于有缓冲chan,我们可以使用 len来获取当前chan使用量,使用cap来获取总chan长度,例如:

我们执行代码后,可知

其他使用方法和无缓冲chan一致。

小案例

我们可以用管道来模拟一下生产者和消费者模型,例如,我们将模型规划为

我们使用管道,能够顺利写出这个demo

我们执行程序结果为

总结

管道(chan)作为我们常用的协程间通信方式之一,我们通常使用make来定义chan,类型可以分为有缓冲和无缓冲2种方式,对于有缓冲管道而言,我们可以写入多个值,直至len== cap容量则会等待,等待有操作向管道读取才会继续写入,通过上述案例就可以看得出,最后注意一旦,使用完管道后,要记得使用close 关闭掉。

猜你喜欢

转载自juejin.im/post/7105696262795558920
今日推荐