目录

文章目录

  • 目录
  • Channel
    • 通道缓冲区
    • 遍历通道与关闭通道

Channel

channel(通道)是用来传递数据的一个数据结构。

通道可用于两个 goroutine 之间通过传递一个指定类型的数值,以此来同步运行及通讯。操作符 <- 用于指定通道的方向,根据位置的不同表示发送或接收。如果未指定方向,则为双向通道。

ch <- v    // 把 v 发送到通道 ch
v := <-ch  // 从 ch 接收数据并把值赋给 v

使用 chan 关键字来定义一个通道变量:

ch := make(chan int)

需要注意的是,默认情况下,通道是不自带缓冲区的。发送端发送数据,就必须同时存在接收端接收相应的数据。

以下示例通过两个 goroutine 来计算数字之和,在 goroutine 完成计算后,它会计算两个结果的和:

package mainimport "fmt"func sum(s []int, c chan int) {sum := 0for _, v := range s {sum += v}c<- sum    // 把 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 并发运行,消费者在 main() 函数的 Goroutine 中进行处理。

package mainimport ("fmt""math/rand""time"
)// 数据生产者
func producer(header string, channel chan<- string) {// 无限循环, 不停地生产数据for {// 将随机数和字符串格式化为字符串发送给通道channel <- fmt.Sprintf("%s: %v", header, rand.Int31())// 等待1秒time.Sleep(time.Second)}
}// 数据消费者
func customer(channel <-chan string) {// 不停地获取数据for {// 从通道中取出数据, 此处会阻塞直到信道中返回数据message := <-channel// 打印数据fmt.Println(message)}
}func main() {// 创建一个字符串类型的通道channel := make(chan string)// 创建producer()函数的并发goroutinego producer("cat", channel)go producer("dog", channel)// 数据消费函数customer(channel)
}

运行结果:

dog: 2019727887
cat: 1298498081
dog: 939984059
cat: 1427131847
cat: 911902081
dog: 1474941318
dog: 140954425
cat: 336122540
cat: 208240456
dog: 646203300

整段代码中,没有线程创建,没有线程池也没有加锁,仅仅通过关键字 “go” 实现 goroutine,和 channel 实现数据交换。

通道缓冲区

通道可以显式设置缓冲区,通过 make 的第二个参数指定缓冲区大小:

ch := make(chan int, 100)

带缓冲区的通道允许发送端的数据发送,和接收端的数据接收处于异步状态,就是说发送端发送的数据可以放在缓冲区里面,然后等待接收端去获取数据,而不是要求接收端立刻去获取数据。

需要注意的是,缓冲区的大小是有限的,所以还是必须要有接收端来接收数据,否则缓冲区一满,数据发送端就无法再发送数据了。

如果通道不带缓冲区,发送端会阻塞直到接收端从通道中接收了值。如果通道带缓冲,发送端则会阻塞直到发送的值被拷贝到缓冲区内;如果缓冲区已满,则意味着需要等待直到某个接收端获取到一个值。接收端在有值可以接收之前会一直阻塞。

package mainimport "fmt"func main() {// 这里我们定义了一个可以存储整数类型的带缓冲通道,缓冲区大小为 2。ch := make(chan int, 2)// 因为 ch 是带缓冲的通道,我们可以同时发送两个数据,而不用立刻需要去同步读取数据。ch <- 1ch <- 2// 获取这两个数据fmt.Println(<-ch)fmt.Println(<-ch)
}

遍历通道与关闭通道

通过 range 关键字还可以用于遍历通道数据类型变量,实现遍历读取到的数据。如果通道接收不到数据,ok 变量则为 false,这时通道就可以使用 close() 函数来关闭一个通道。

package mainimport "fmt"func fibonacci(n int, c chan int) {x, y := 0, 1for i := 0; i < n; i++ {c <- xx, y = y, x + y}close(c)
}func main() {c := make(chan int, 10)go fibonacci(cap(c), c)/*** range 函数遍历每个从通道接收到的数据,* 因为 c 在发送完 10 个数据之后就关闭了通道,* 所以这里我们 range 函数在接收到 10 个数据之后就结束了。* 如果上面的 c 通道不关闭,那么 range 函数就不会结束,从而在接收第 11 个数据的时候就阻塞了。*/for i := range c {fmt.Println(i)}
}

Go 语言编程 — 并发 — Channel 通道相关推荐

  1. Go 语言编程 — 并发 — GMP 调度模型

    目录 文章目录 目录 并发和并行 如何交互?CSP 通信模型 如何调度?GMP 调度模型 用户级线程模型(多对一) 内核级线程模型(一对一) 两级线程模型(多对多) GMP 线程模型 Go Runti ...

  2. Go 语言编程 — 并发 — 同步原语与锁

    目录 文章目录 目录 协程锁 协程锁 协程锁主要用于保证在执行 goroutine 的时候不阻塞 M. 举例:任务 A 需要修改 Z,任务 B 也需要修改 Z.如果是串行系统,A 执行完了,再执行B, ...

  3. Go 语言编程 — 并发 — Goroutine 协程

    目录 文章目录 目录 Golang 的协程 go 关键字 Golang 的协程 Golang 的协程被称为 Goroutine.因为操作系统内核是不感知协程的,也就是说 Golang 需要自己实现一个 ...

  4. Go语言编程:使用条件变量Cond和channel通道实现多个生产者和消费者模型

    如题,使用条件变量Cond和channel通道实现多个生产者和消费者模型.Go语言天生带有C语言的基因,很多东西和C与很像,但是用起来 绝对比C语言方便.今天用Go语言来实现下多消费者和生产者模型.如 ...

  5. golang并发编程goroutine+channel(一)

    go语言的设计初衷除了在不影响程序性能的情况下减少复杂度,另一个目的是在当今互联网大量运算下,如何让程序的并发性能和代码可读性达到极致.go语言的并发关键词 "go" go dos ...

  6. 使用 Go 语言进行并发编程的实践方法

    Go语言是一门开源的编程语言,由谷歌公司开发.它的特点是非常适合进行并发编程,这使得它在云计算.分布式系统.网络编程.大数据等领域得到了广泛应用.在本文中,我将介绍Go语言的并发编程实践方法,包括并发 ...

  7. 关于Go并发编程,你不得不知的“左膀右臂”——并发与通道!

    导语 | 并发编程,可以说一直都是开发者们关注最多的主题之一.而Golang作为一个出道就自带"高并发"光环的编程语言,其并发编程的实现原理肯定是值得我们深入探究的.本文主要介绍G ...

  8. Java语言进阶:Channel(通道)

    Java语言进阶:Channel(通道) Channel概述 Channel(通道):Channel是一个接口,可以通过它读取和写入数据, 可以把它看做是IO中的流,不同的是:Channel是双向的, ...

  9. JAVA NIO:NIO与OIO的对比以及Channel通道、Selector选择器、Buffer缓冲区的介绍 高并发

    文章目录 二 Java NIO (一)NIO对比OIO (二)概述三个核心组件 Channel通道 Selector选择器 Buffer缓冲区 (三)Buffer详解 1 Buffer类 2 四个属性 ...

最新文章

  1. android不调用系统发送短信,android之两种方式调用短信发送接口
  2. 【转】【WPF】WPF样式(Style)—触发器
  3. jQuery HighchartsTableHTML表格转Highcharts图表插件
  4. TensorRT学习笔记6 - IPlugin
  5. 枚举类型(C# 编程指南)
  6. AAAI 2022 | 可解释和鲁棒的联合文本分类及证据提取
  7. USB应用开发笔记之一:STM32上实现USB主机读写U盘
  8. 题目1001:A+B for Matrices
  9. 什么是应用管理与运维平台(ServiceStage)?
  10. ASP.NET Web API 上传文件
  11. C# 程序异常关闭时的捕获
  12. SSH学习之二 OpenSSH配置文件解析
  13. oracle官方文档下载使用
  14. MATLAB图像的读取和显示
  15. 反射机制,类的加载机制,和注解的配置参数的结合使用详解
  16. PowerApps 中的单选控件
  17. mysql中默认值_和comment_MySQL字段默认值踩坑记录
  18. 卡农,用敬仰和泪水思念着你~~~~~
  19. mysql存储图片node_Node.js教程 阿里云mysql如何支持存储emoji表情
  20. 他一年开发19款!款款口碑爆棚

热门文章

  1. iOS10 UI教程管理层次结构
  2. Xamarin iOS教程之编辑界面编写代码
  3. python 设计 实践_python实践设计模式(一)概述和工厂模式
  4. spark官方文档_Apache Spark 文档传送门
  5. 项目跑到到了日志警告就卡住了_java中的日志框架梳理(以故事的形式呈现)...
  6. hibernate jar包_源码分析 | 咋嘞?你的IDEA过期了吧!加个Jar包就破解了为什么?
  7. 4 app版本号 swift_已开源 app 实现检查更新的简单方式
  8. Logistics回归数据集(testSet.txt)《机器学习实战》【美】Peter Harrington python3.6+pycharm完美实现代码
  9. 机器学习博士自曝:实验室「阉割」我的创造力,劝你别读!
  10. 美国疫情加剧:特朗普检测虚惊一场,女儿伊万卡开始“隔离”,马云捐助百万口罩...