制坯系列-Golang专题-chan
《制坯系列-Golang专题》:chan作为协程之间通信的重要方式,是替代内存共享的最佳通信方式,本文对基本原理和关键知识点做简单介绍
chan底层数据结构
type hchan struct {qcount uint // 当前队列中剩余元素个数dataqsiz uint // 环形队列长度,即可以存放的元素个数buf unsafe.Pointer // 环形队列指针elemsize uint16 // 每个元素的大小,用于在buf中定位元素位置。closed uint32 // 标识关闭状态elemtype *_type // 元素类型,用于数据传递过程中的赋值sendx uint // 队列下标,指示元素写入时存放到队列中的位置recvx uint // 队列下标,指示元素从队列的该位置读出recvq waitq // 等待读消息的goroutine队列sendq waitq // 等待写消息的goroutine队列lock mutex // 互斥锁,chan不允许并发读写
}
缓存区环形队列
- dataqsiz指示了队列长度为6,即可缓存6个元素;
- buf指向队列的内存,队列中还剩余两个元素;
- qcount表示队列中还有两个元素;
- sendx指示后续写入的数据存储的位置,取值[0, 6);
- recvx指示从该位置读取数据, 取值[0, 6);
等待队列
阻塞:
- 如果从缓冲区为空或则没有缓冲区的channel中读取数据,当前协程会加入recvq队列
- 如果向缓冲区已满或则没有缓冲区的channel中写入数据,当前协程会加入sendq队列
唤醒:
- 因读取阻塞的协程会被向channel中写入数据的协程唤醒
- 因写入阻塞的协程会被从channel中读取数据的协程唤醒
chan的操作
chan的创建
golang创建chan的代码示例
var ch1 chan int // 声明,值为nil
var ch2 = make(chan int) // 创建,不带缓冲区
var ch3 = make(chan int, 1) // 创建,带缓冲区
chan的底层创建:创建channel的过程实际上是初始化hchan结构
func makechan(t *chantype, size int) *hchan {var c *hchanc = new(hchan)c.buf = malloc(元素类型大小*size)c.elemsize = 元素类型大小c.elemtype = 元素类型c.dataqsiz = sizereturn c
}
向channel写数据
- 如果等待接收队列recvq不为空,说明缓冲区中没有数据或者没有缓冲区,此时直接从recvq取出G,并把数据写入,最后把该G唤醒,结束发送过程;
- 如果缓冲区中有空余位置,将数据写入缓冲区,结束发送过程;
- 如果缓冲区中没有空余位置,将待发送数据写入G,将当前G加入sendq,进入睡眠,等待被读goroutine唤醒;
从channel读数据
- 如果等待发送队列sendq不为空,且没有缓冲区,直接从sendq中取出G,把G中数据读出,最后把G唤醒,结束读取过程;
- 如果等待发送队列sendq不为空,此时说明缓冲区已满,从缓冲区中首部读出数据,把G中数据写入缓冲区尾部,把G唤醒,结束读取过程;
- 如果缓冲区中有数据,则从缓冲区取出数据,结束读取过程;
- 将当前goroutine加入recvq,进入睡眠,等待被写goroutine唤醒;
关闭channel
关闭channel时会把recvq中的G全部唤醒,本该写入G的数据位置为nil。把sendq中的G全部唤醒,但这些G会panic。
channel操作中的阻塞和panic
阻塞
- 从nil管道中读取数据
- 从无缓冲区或则缓冲区已满的管道中读取数据
- 向nil管道中写入数据
- 向无缓冲区或则缓冲区已满的管道中写入数据
panic
- 位于协程中sendq队列中的协程会在关闭channel时触发panic
- 关闭值为nil的管道
- 关闭已被关闭的管道
- 向已经关闭的管道写入数据
管道的常见用法
单向channel
func readChan(chanName <-chan int) { // 通过形参限定函数内部只能从channel中读取数据<- chanName
}
func writeChan(chanName chan<- int) { // 通过形参限定函数内部只能向channel中写入数据chanName <- 1
}
func main() {var mychan = make(chan int, 10)writeChan(mychan)readChan(mychan)
}
select
使用select可以监控多channel,比如监控多个channel,当其中某一个channel有数据时,就从其读出数据。
case的选择为随机,如果所有case均阻塞则选择default,如果没有default则select阻塞
package main
import ("fmt""time"
)
func addNumberToChan(chanName chan int) {for {chanName <- 1time.Sleep(1 * time.Second)}
}
func main() {var chan1 = make(chan int, 10)var chan2 = make(chan int, 10)go addNumberToChan(chan1)go addNumberToChan(chan2)for {select {case e := <- chan1 :fmt.Printf("Get element from chan1: %d\n", e)case e := <- chan2 :fmt.Printf("Get element from chan2: %d\n", e)default:fmt.Printf("No element in chan1 and chan2.\n")time.Sleep(1 * time.Second)}}
}
for-range
通过range可以持续从channel中读出数据,好像在遍历一个数组一样,当channel中没有数据时会阻塞当前goroutine,与读channel时阻塞处理机制一样。
func chanRange(chanName chan int) {for e := range chanName {fmt.Printf("Get element from chan: %d\n", e)}
}
制坯系列-Golang专题-chan相关推荐
- 1112: 进制转换(函数专题)
1112: 进制转换(函数专题) 时间限制: 1 Sec 内存限制: 128 MB 提交: 3448 解决: 2599 [提交] [状态] [讨论版] [命题人:admin] 题目描述 输入一个十进制 ...
- ZZULIOJ 1112: 进制转换(函数专题)
进制转换(函数专题) 题目描述 输入一个十进制整数n,输出对应的二进制整数.常用的转换方法为"除2取余,倒序排列".将一个十进制数除以2,得到余数和商,将得到的商再除以2,依次类推 ...
- golang 学习 - chan以及chan的一下用例
golang 学习 - chan 1. 通道 // _通道_ 是连接多个 Go 协程的管道.你可以从一个 Go 协程 // 将值发送到通道,然后在别的 Go 协程中接收.package mainimp ...
- golang的chan(管道)
golang的chan翻译成中文就是管道,顾名思义,就是管道的一端用来读,另一端用来写,这与write和read函数的性质是非常相似的,比如说管道中没数据,就会发生读阻塞,管道中数据是满的,就会发生写 ...
- CP2K+Gaussian+LAMMPS+ReaxFF计算材料化学系列四大专题。
背景: CP2K是一款较为强大的AIMD计算程序,免费开源,可高效并行.由于CP2K在做DFT时可以速度非常快地计算成千上万个原子的体系,因此在大规模模拟体系中经常被一些学者用到.比如计算原子数达到一 ...
- 【ZZULIOJ】1112: 进制转换(函数专题)
ZZULIOJ题解 1112: 进制转换(函数专题) 题目描述 输入一个十进制整数n,输出对应的二进制整数.常用的转换方法为"除2取余,倒序排列".将一个十进制数除以2,得到余数和 ...
- golang管道chan
package mainimport ("fmt""time" )func main() {//test2()test4()time.Sleep(time.Se ...
- golang基础-chan的select操作、定时器操作、超时控制、goroutine中使用recover
chan的只读和只写 a.只读chan的声明 Var 变量的名字 <-chan int Var readChan <- chan int b. 只写chan的声明 Var 变量的名字 ch ...
- [易学易懂系列|golang语言|零基础|快速入门|(一)]
golang编程语言,是google推出的一门语言. 主要应用在系统编程和高性能服务器编程,有广大的市场前景,目前整个生态也越来越强大,未来可能在企业应用和人工智能等领域占有越来越重要的地位. 本文章 ...
最新文章
- Mac下编译ffmpeg出现“ERROR: x265 not found using pkg-config”
- 读写xml节点的数据总结
- 用官方2012版本131兆,一共有四个自带软件
- react 使用 mobx_如何使用React和MobX状态树构建基于状态的路由器
- mysql数据库表名批量改为小写,MySQL 批量修改表名
- rabbitmq消息保证幂等的消息设计
- sqlserve生成随机数
- ArcGIS导出shape地图边界点数据
- python 画直方图
- php 双竖线,范数介绍,数字两边双竖线
- 计算机核心论文如何审稿,计算机核心期刊排名及投稿经验(范文).doc
- 突发!蚂蚁集团CEO宣布辞职,阿里方面表示属实!
- python-函数的递归
- CSS 网页背景图片设置
- 爬取北京链家二手房(requests和selenium)
- 用Python打造你的专属情人节贺卡,赶快发给TA浪漫一下吧
- 184. 部门工资最高的员工
- 3dmax和python做3d动画_ThingJS问答录 | 三维动画师和程序员的职业前景 3D 可视化
- 如何把录音转换成文字?这几个方法可以轻松解决录音转文字
- 易语言python模块_Python获取指定模块基址
热门文章
- iOS字体像数与磅的对应关系
- vue引入echarts-liquidfill水滴图并批量动态加载
- kali2022.1安装google chrome develop 专业版
- 解决win2008 R2远程桌面授权过期的方法
- available: expected at least 1 bean which qualifies as autowire candidate
- 含并行连结的网络 GoogLeNet / Inception V3 动手学深度学习v2 pytorch
- 类和对象(Java)
- nanopore测序技术专题(一):为什么要选择nanopore测序?
- 12.2 数据库控制文件复制到ASM磁盘组
- 《大数据》第1期“专题”——大数据与智慧城市