今天是golang专题的第14篇文章,大家可以点击上方的专辑回顾之前的内容。

今天我们来看看golang当中另一个很重要的概念——信道。我们之前介绍goroutine的时候曾经提过一个问题,当我们启动了多个goroutine之后,我们怎么样让goroutine之间保持通信呢?

要回答这个问题就需要用到信道。

channel

信道的英文是channel,在golang当中的关键字是chan。它的用途是用来在goroutine之间传输数据,这里你可能要问了,为什么一定得是goroutine之间传输数据呢,函数之间传递不行吗?

因为正常的传输数据直接以参数的形式传递就可以了,只有在并发场景当中,多个线程彼此隔离的情况下,才需要一个特殊的结构传输数据。

Chan看起来比较怪,在其他语言当中基本没有出现过,但是它的原理和使用都非常简单。

我们先来看它的使用,首先是定义一个chan,还是老规矩,通过make关键字创建。我们之前也提过,golang当中的一个设计原则就是能省则省,能简单则简单。从这个make关键字就看得出来,它可以创建的东西太多了,既可以创建一个切片,也可以创建map,还可以创建信道。

所以当我们要创建一个chan的时候,可以通过make实现。

Ch := make(chan int)

我们在chan后面跟上一个类型,表示这个信道传输的数据类型。如果你想要传输任何类型呢,那可以用我们之前说过的interface{}。

Chan创建了之后,我们想要从其中获取数据或者是把数据放入其中也非常简单,简单到都没有api,直接用形象的传输语句就可以了。

比如我们现在有一个chan是ch,我们想要放入数据,我们可以这样ch <- a。我们想要从ch当中获取数据,我们可以v := <- ch。

我们用箭头表示数据的流动,是不是很形象很直观呢?

阻塞

但是还没完,chan有一个很关键的点在于,chan的使用是阻塞的。也就是说下游从chan当中拿走一个数据我们才可以传入一个数据。否则的话,传输数据的代码就会一直等待chan清空。

同样,如果我们定义了一个从chan当中读取数据的语句,假如当前的chan是空的话,那么它也会一直阻塞等待,直到chan当中有数据了为止。

所以我们就知道了,chan的使用场景当中需要一个生产方,也需要一个消费方。我们来看一个golang官方的一个例子:

package main

import "fmt"

func sum(s []int, c chan int) {
 sum := 0
 for _, v := range s {
  sum += v
 }
 c <- sum // 将和送入 c
}

func main() {
 s := []int{7, 2, 8, -9, 4, 0}

 c := make(chan int)
 go sum(s[:len(s)/2], c)
 go sum(s[len(s)/2:], c)
 x, y := <-c, <-c // 从 c 中接收

 fmt.Println(x, y, x+y)
}

我们启动了两个goroutine去对数组进行求和并进行返回,goroutine生产的数据是没办法直接return的,所以只能通过chan的形式传输出来。chan传输出来需要下游消费,所以上面两个goroutine的数据会传输到x, y: <-c, <-c 这一句语句当中。

前面说过了,chan的传输是阻塞的,所以这一句语句会一直等待,直到上面两个goroutine都计算完成了为止。

如果你看的有些发蒙,觉得好似有些理解了又好似没有的话,那么很简单的一个办法是在理解的时候把这个使用场景做一个变幻。把chan的使用场景想象成我们之前介绍过的生产者消费者设计模式,chan在其中扮演的角色其实就是队列。

生产者往队列当中传输数据,消费者进行消费,唯一不同的是这个队列的容量是1,必须要生产和消费端都准备就绪了才会进行数据传输。

chan的缓冲

前文说了,chan的容量只有1,只有消费端和生产端都就绪的时候才可以传输数据。我们也可以给chan加上缓冲,如果消费端来不及把所有的数据都消费完,允许生产端先把数据暂时存在chan当中,先不发生阻塞,只有在chan满了之后才会阻塞。

用法也很简单,我们在通过make创建chan的时候多加上一个参数表示容量即可,和我们之前创建切片的道理很类似。

Ch := make(chan int, 100)

比如这样,我们就创建了一个缓冲区为100的信道。

但多说一句,其实这种情况不太常用,原因也很简单。因为上下游的消费情况是统一的,如果生产者生产的速度过快,而消费端跟不上的话,即使把它先暂存在缓冲区当中也没什么用,早晚还是会要阻塞的。

close

当我们对信道使用结束之后,可以通过close语句将它关闭。

Close这个操作只能在生产端进行,消费端如果close信道会引发一个panic。我们在从chan接收数据的时候,可以加上一个参数判断信道是否关闭。

v, ok := <- ch
if !ok {
 return
}

这样我们就可以判断chan关闭的时间了。

今天的文章到这里就结束了,如果喜欢本文的话,请来一波素质三连,给我一点支持吧(关注、转发、点赞)。

相关阅读

Python | 面试的常客,经典的生产消费者模式

原文链接,求个关注

- END -

Golang | 简介channel常见用法,完成goroutin通信的更多相关文章

  1. 【c++】标准模板库STL入门简介与常见用法

    一.STL简介 1.什么是STL STL(Standard Template Library)标准模板库,主要由容器.迭代器.算法.函数对象.内存分配器和适配器六大部分组成.STL已是标准C++的一部 ...

  2. 深入学习golang(2)—channel

    Channel 1. 概述 “网络,并发”是Go语言的两大feature.Go语言号称“互联网的C语言”,与使用传统的C语言相比,写一个Server所使用的代码更少,也更简单.写一个Server除了网 ...

  3. [HMLY]9.深入浅出-iOS Reactive Cocoa的常见用法

    简介 今天的主角是Reactive Cocoa,聊聊Reactive Cocoa的常见使用:KVO.Target.Delegate.Notification. Reactive Cocoa 是一个重量 ...

  4. golang 的 http cookie 用法

    golang的http cookie用法 在服务端程序开发的过程中,cookie经常被用于验证用户登录.golang 的 net/http 包中自带 http cookie的定义,下面就来讲一下coo ...

  5. golang的Channel

    golang的Channel Channel 是 golang 一个非常重要的概念,如果你是刚开始使用 golang 的开发者,你可能还没有真正接触这一概念,本篇我们将分析 golang 的Chann ...

  6. Golang 入门 : channel(通道)

    笔者在<Golang 入门 : 竞争条件>一文中介绍了 Golang 并发编程中需要面对的竞争条件.本文我们就介绍如何使用 Golang 提供的 channel(通道) 消除竞争条件. C ...

  7. golang中type常用用法

    golang中,type是非常重要的关键字,一般常见用法就是定义结构,接口等,但是type还有很多其它的用法,在学习中遇到了以下几种,这点简单总结记录下 定义结构 type Person struct ...

  8. golang的channel实现

    golang的channel实现位于src/runtime/chan.go文件.golang中的channel对应的结构是: // Invariants: // At least one of c.s ...

  9. golang的select典型用法

    golang 的 select 的功能和 select, poll, epoll 相似, 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作. 示例: ch1 := make (chan in ...

随机推荐

  1. 数据量大了一定要分表,分库分表组件Sharding-JDBC入门与项目实战

    最近项目中不少表的数据量越来越大,并且导致了一些数据库的性能问题.因此想借助一些分库分表的中间件,实现自动化分库分表实现.调研下来,发现Sharding-JDBC目前成熟度最高并且应用最广的Java分 ...

  2. python 变量的命名规则和注意事项

    命名规则 变量名只能包含字母.数字和下划线.变量名可以字母或下划线打头,但不能以数字打头,例如,可将变量命名为message_1,但不能将其命名为1_message 变量名不能包含空格,但可使用下划线 ...

  3. -bash: !": event not found

    在linux环境下执行一下代码时 printf "The first '%s,%s!' \n" Hello world 返回结果为“-bash: !”: event not fou ...

  4. JS 获取验证码按钮改变案例

    HTML代码 <div class="box"> <label for="">手机号</label> <input t ...

  5. 一个试图了解JVM内存模型的两年经验的初级程序员,透彻!

    所有的编程语言中都有内存模型这个概念,区别于微架构的内存模型,高级语言的内存模型包括了编译器和微架构两部分.我试图了解了Java.C#和Go语言的内存模型,发现内容基本大同小异,只是这些语言在具体实现 ...

  6. 关于GPU你必须知道的基本知识

    图形处理单元(或简称GPU)会负责处理从PC内部传送到所连接显示器的所有内容,无论你在玩游戏.编辑视频或只是盯着桌面的壁纸,所有显示器中显示的图像都是由GPU进行渲染的. 对普通用户来说,实际上不需要 ...

  7. CSS3 新添选择器

    目录 属性选择器 结构伪类选择器 伪元素选择器 属性选择器 属性选择器可以元素特定属性来进行选择,这样就可以不借助于类选择器或id选择器 选择符 简述 E[att] 选择具有att属性的E元素 E[a ...

  8. 提前批笔试一道算法题的Java实现

    题目描述 这是2021广联达校招提前批笔试算法题之一. 我们希望一个序列中的元素是各不相同的,但是理想和显示往往是有差距的.现在给出一个序列A,其中难免有相同的元素,现在提供了一种变化方式,使得经过若 ...

  9. 文件上传控件bootstrap-fileinput中文设置没有效果的情况

    1.引入zh.js顺序错误 zh.js需放到fileinput.js下面 2. 组件创建语法错误 (class=“file”) 如果你使用js初始化fileinput组件,那么在html元素中应删除 ...

  10. 攻防世界-web(进阶)-NaNNaNNaNNaN-Batman

    用winhex打开,发现是一个javascript代码.将文件重命名为html文件,用浏览器打开. 打开是一个输入框,输入任何东西都梅反应,尝试弹框输入也无果,继续查看代码. 查看代码,可以看到最开始 ...