首页 > 其他分享 >golang channel

golang channel

时间:2023-11-16 20:34:36浏览次数:30  
标签:发送 goroutine chan golang go close channel

”不要以共享内存的方式来通信,相反,要通过通信来共享内存“
golang 的一个思想,不整文的,整点武的,具体来看channel 怎么做的
有一个很关键的 golang MPG 模型再单独分析,这篇先只分析 channel

定义

// runtim/chan.go

type hchan struct {
	qcount   uint           // 通道里的元素数量
	dataqsiz uint           // 通道的总大小
	buf      unsafe.Pointer // 通道底层循环数组的指针
	elemsize uint16 // 每个元素的大小
	closed   uint32 // 通道是否关闭,不能重复关闭,会 panic
	elemtype *_type // 通道里元素的类型
	sendx    uint   // 通道里发送元素的下标
	recvx    uint   // 接受元素的下标
	recvq    waitq  // 准备接受的协程链表
	sendq    waitq  // 准备发送的写成链表

	lock mutex // 通道锁,chan 是并发安全的
}

链表,保存发送或接受协程

// runtim/chan.go

type waitq struct {
	first *sudog
	last  *sudog
}

初始化

channel使用 make 初始化

c  := make(chan int) // 无缓冲
c2 := make(chan int,10) // 有缓冲

当无缓冲时,直接创建,当有缓冲时,还要调用 mallocgc 函数,申请空间,具体代码可以看 runtime/chan.go

发送数据

使用来说很简单,下面的代码如果 channel 满了或者无缓冲无接受者的话就会阻塞

c <- 10

具体发送代码在 runtime/chan.go(chansend) 函数,就不贴代码了,直接分析流程

除了必要的一些检查之外,先对 channel 进行加锁,如果 channel 已经关闭了,就解锁退出
然后判断接收区有没有 goroutine 在等待,如果有的话,直接把数据拷贝给接收区的 goroutine,然后唤醒 goroutine
否则看缓冲区是否满了,如果没满,就把数据拷贝到缓冲区sendx处,然后 sendx++,qcount++,退出
如果缓冲区也满了,则把发送的 goroutine 放入到发送 sendq 队列
一个流程就结束了

接受数据

x := <- c

具体关闭代码在 runtime/chan.go(chanrecv)

先进行检查,判断 channel 是否是空的,如果是空的直接返回(判空条件是qcount == 0 并且sendq里没有 goroutine)
然后加锁
然后判断 channel 是否已经关闭,关闭的话直接返回变量类型的空值
如果缓冲区有数据,则直接拷贝缓冲区数据到接受,recvx++,qcount--
如果上述都不符合,则把接受goroutine 保存到接受队列

关闭通道

close(c)

源码在 runtime/chan.go(closechan)

先加锁,如果已经关闭了,则 panic
然后将 close 置为 1
把所有的接受队列填充空值并唤醒
把所有的发送队列唤醒,让他们 panic

各种情况处理

close 一个正常的 channel 会正常,否则都会 panic,也就是 close 只能正确的调用一次
发送一个 close 的 channel 会 panic,发送一个 nil 的 channel 会一直阻塞
接受一个 close 的 channel 会接受到 0 值,接受一个 nil 的 channel 会一直阻塞

参考

Go 程序员面试笔试宝典-通道
图解Golang channel源码
Go面试题(五):图解 Golang Channel 的底层原理

标签:发送,goroutine,chan,golang,go,close,channel
From: https://www.cnblogs.com/elve960520/p/17837202.html

相关文章

  • golang map
    golang的map使用的是hashmap基本结构下面截取自源码,已翻译//runtime/map.go:117//gomap定义,hashmap缩写typehmapstruct{ countint//map里文件数 flagsuint8//map当前是否在写入,一般为hashWriting=4(写入中)或0(空闲) Buint8......
  • 部署基于 mt-channel-broker 的 broker
    安装in-memory-channel下载in-memory-channel#wgethttps://github.com/knative/eventing/releases/download/knative-v1.12.0/in-memory-channel.yaml替换gcr.io #sed-i'[email protected]@gcr.dockerproxy.com@g'in-memory-channel.yaml创建in-memory-channel资源#k......
  • Golang把文件写到excel
    最近有个需求是把看广告的日志转成excelpackagemainimport( "bufio" "encoding/json" "flag" "fmt" "github.com/xuri/excelize/v2" "os" "time")//Ad广告typeAdstruct{ OpenIdstring`json:&quo......
  • 使用golang对服务器简单监控
    packagemainimport( "fmt" "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/disk" "github.com/shirou/gopsutil/host" "github.com/shirou/gopsutil/load" "github.com/shirou/gopsutil/me......
  • 从一道题来看看golang中的slice作为参数时的现象
    1、题目最近看群友在群里问一道关于golang中slice的题,题目如下:packagemainimport"fmt"funcmain(){ k:=[]int{1,2,3,4} k=append(k,5,6) fmt.Printf("k-->value:%v,add:%p,cap:%d\n",k,k,cap(k)) ap(k) fmt.Printf("k-->value......
  • NS-3源码学习(二)Channel和NetDevice
    NS-3源码学习(二)Channel和NetDevice对于一个新的802.11协议的实现,仅需要完成对两个抽象类的实现即可,一个是Channel抽象类,一个是NetDevice接口,这两个类对上层来说是透明的,而且据我查阅代码了解,这两个类仅需知道上一层(网络层)是IPv4协议还是IPv6协议即可,并没有对上层有更高的要求。M......
  • windows系统使用终端和goland编辑器打包golang程序方法
    上一篇文章说了,windows系统,如何使用goland编辑器打包exe和linux程序,这篇文章再补充一下,使用终端和goland编辑器打包的对比情况。这里的终端可以是,cmd、WindowsPowerShell、MINGw64这里,我使用goland编辑器里面的Terminal,也就是WindowsPowerShelll来操作1、goland编辑器打......
  • 【golang】Golang 哈希码 hashcode 输入一个字符串,得到一个唯一标识码
    如何输入一个字符串,得到一个唯一的hashcode?例子如下:packagemainimport("fmt""hash/crc32")//Stringhashesastringtoauniquehashcode.////crc32returnsauint32,butforouruseweneed//andnonnegativeinteger.Herewec......
  • golang slice
    slice是golang的切片,动态数组底层结构//runtime/slice.gotypeslicestruct{ arrayunsafe.Pointer//底层数组 lenint capint}golang的slice底层是一个数组,也就是可以通过&s[0]来获取底层数组的地址,len记录的当前,cap记录的是底层数组的大小也就是当前......
  • golang版本升级(Mac GoLand版)
    本地的go版本是1.18,想升级到1.21,运用GoLand做快速升级第一步  进入GoLand-》Preferences第二步  进入Go-〉GOROOT点击“+”号,选择“Download”第三步选择需要更新的版本 点击“OK”后“Apply”,最新版的go就会下载到你的GOPATH里面了 升级完新版本后,deb......