Golang利用channel协调协程的方法详解
作者:JetTsang 发布时间:2024-05-08 10:21:54
标签:Go,channel,协程
前言
go 当中的并发编程是通过goroutine
来实现的,利用channel(管道)
可以在协程之间传递数据,实现协程的协调与同步。
使用
新建一个管道,使用make channel
来构建
// 构建一个缓存长度为8 的管道
ch := make(chan int ,8)
// 写入
ch <- 10
// 取出
number := <-ch
// 关闭
close(ch)
注意: 取数据的时候,如果没得取,会阻塞代码的执行,如果一直没有取到,那就是死锁
实现生产者消费者模式
两个生产者者协程和一个消费者协程
使用waitGroup
func main() {
ch := make(chan int, 100)
wg := sync.WaitGroup{}
wg.Add(2)
// 生产者
go func() {
defer wg.Done()
// 写入数据
for i := 0; i < 10; i++ {
ch <- i
}
}()
// 生产者
go func() {
defer wg.Done()
// 写入数据
for i := 0; i < 10; i++ {
ch <- i
}
}()
wg2 := sync.WaitGroup{}
wg2.Add(1)
// 消费者
go func() {
sum := 0
fmt.Printf("sum %d \n", sum)
for {
// 这里会等待
temp, ok := <-ch
// close 并且 管道为空,ok = false
if !ok {
break
} else {
sum += temp
}
}
fmt.Printf("sum %d \n", sum)
wg2.Done()
}()
// 等待俩生产者结束
wg.Wait()
// 生产数据之后,消费者也并行读完了,此时可以关闭 管道 来 跳出for循环了
close(ch)
// 等待消费者协程结束
wg2.Wait()
}
使用管道则将wg2相关的代码改掉
func main() {
//...
//...
ch2 := make(chan struct{}, 0)
go func() {
sum := 0
fmt.Printf("sum %d \n", sum)
for {
// 这里会等待
temp, ok := <- ch
// close 并且 管道为空,ok = false
if !ok {
break
} else {
sum += temp
}
}
fmt.Printf("sum %d \n", sum)
ch2 <- struct{}{}
}()
// 等待俩生产者结束
wg.Wait()
// 关闭管道
close(ch)
// 等待消费者协程结束
<-ch2
}
实战面试题: 「交替打印数字和字母」
题目
使用两个 goroutine
交替打印序列,一个 goroutine
打印数字, 另外一个 goroutine
打印字母, 最终效果如下:
12AB34CD56EF78GH910IJ1112KL1314MN1516OP1718QR1920ST2122UV2324WX2526YZ2728
解题思路
利用channel的 阻塞 来协调线程,达到线程交叉执行的效果。
代码
func main() {
letter, number := make(chan bool), make(chan bool)
wait := sync.WaitGroup{}
go func() {
i := 1
for {
if <-number {
fmt.Print(i)
i++
fmt.Print(i)
i++
letter <- true
}
}
}()
wait.Add(1)
go func() {
// 获得ASCII码
i := 'A'
for {
if <-letter {
// 当前已经超过Z时,无需再打印
if i > 'Z' {
// 停止等待,并且跳出循环
wait.Done()
break
}
// 将ASCII码强转成字母输出
fmt.Print(string(i))
i++
fmt.Print(string(i))
i++
number <- true
}
}
}()
// 放行数字打印的阻塞
number <- true
// 等待关闭主线程
wait.Wait()
}
其实完全也可以将waitGroup
换成管道
func main() {
letter, number := make(chan bool), make(chan bool)
// 再定义一个管道来等待,替代waitGroup的作用
wait := make(chan bool)
// 打印数字
go func() {
i := 1
for {
if <-number {
fmt.Print(i)
i++
fmt.Print(i)
i++
letter <- true
}
}
}()
// 打印字母
go func() {
// 获得ASCII码
i := 'A'
for {
if <-letter {
if i > 'Z' {
wait <- true
break
}
// 将ASCII码强转成字母输出
fmt.Print(string(i))
i++
fmt.Print(string(i))
i++
number <- true
}
}
}()
number <- true
// 等待管道取值
<- wait
}
来源:https://juejin.cn/post/7236670763271798842


猜你喜欢
- python:如何将excel文件转化成CSV格式import pandas as pddata = pd.read_excel('
- 在大多数场景中,我们都用 lxml 库解析网页源码,但你是否知道,lxml 库也是可以操作 svg 图片的。我们可以使用
- 前段时间用C语言做了个字符版的推箱子,着实是比较简陋。正好最近用到了Python,然后想着用Python做一个图形界面的推箱子。这回可没有C
- Github 项目主页 工具源码分析结果:total : 15981 1568.0 == Backspace 1103.0 == Tab 1
- 本文实例讲述了JS简单实现DIV相对于浏览器固定位置不变的方法。分享给大家供大家参考,具体如下:<!DOCTYPE HTML PUBL
- 本文实例为大家分享了python实现图像拼接的具体代码,供大家参考,具体内容如下1.待拼接的图像2. 基于SIFT特征点和RANSAC方法得
- 前言:我们先定义一个test01.py的文件。test01.py中代码如下所示:def step():print(__name__) &nb
- try { int readByte = 0;  
- generator-vue-component可以快速生成自己的组件开发的脚手架,类似于vue-cli生成vue项目,这脚手架是目录结构是方
- 4 月 27 日,GitHub 趋势榜第 3 位是一个用 Python 编码实现的算法库,Star 数早已达到 26000+链接:https
- 本文实例讲述了Python Excel表格创建乘法表。分享给大家供大家参考,具体如下:题目如下:创建程序multiplicationTabl
- 了解如何 在sublime编辑器中安装python软件包,以 实现自动完成等功能,并在sublime编辑器本身中运行build。安装Subl
- js 代码中经常会碰到 undefined 这种错误,下面本文分享一下为什么会发生这种错误以及如何处理这种错误,js 中如果通过 var 声
- linux安装mysql服务分两种安装方法:①源码安装,优点是安装包比较小,只有十多M,缺点是安装依赖的库多,安装编译时间长,安装步骤复杂容
- 一、概念说明柱状图(bar chart),从相同的横坐标出发,以不同的数值大小来设定柱子的高度,进而表示无序或有序的定性数据间某个定量指标的
- 需求最近接到一个任务,要把一批文件中的十几万条JSON格式数据写入到Oracle数据库中,Oracle是企业级别的数据库向来以高性能著称,所
- sql server 数据库,sa用户被锁定1、打开数据库——用Windows身份登录数据库2、登录名——双击sa(打开属性)3、常规——设
- 之前也写过这个小组件,最近遇到select下加搜索的功能,所以稍微完善一下。效果图:子组件 dropdown.vue<template
- 在获得网页响应对象res后,使用res.text属性可以获得网页源代码,但可能出现乱码!因为requests库会使用自动猜测的解码方式将抓取
- 目录背景认识复合索引最左匹配原则字段顺序的影响复合索引可以替代单一索引吗?小结背景最近频繁出现慢SQL导致系统性能问题,于是决定针对索引进行