Golang-channel合集——源码阅读、工作流程、实现原理、已关闭channel收发操作、优雅的关闭等面试常见问题。

前言

面试被问到好几次“channel是如何实现的”,我只会说“啊,就一块内存空间传递数据呗”…所以这篇文章来深入学习一下Channel相关。从源码开始学习其组成、工作流程及一些常见考点。

NO!共享内存

Golang的并发哲学是“不要通过共享内存的方式进行通信,而是应该通过通信的方式共享内存。”

共享内存会需要使用锁、信号量等方式去控制访问,保障内存的一致性。所以会导致性能损耗+同步问题复杂。

“通过通信来共享内存”的理念强调在并发单元之间通过消息传递来交换数据,而不是直接共享内存。这样,每个并发单元都有自己的内存,不与其他并发单元共享。当它们需要共享数据时,它们会通过发送消息来完成。这种方法的优点是避免了使用锁和同步机制,从而降低了死锁和竞态条件的风险,简化了并发程序的设计和理解。

Channel整体结构

源码位置

位于src/runtime下的chan.go中。

在这里插入图片描述

Channel整体结构图

图源:https://i6448038.github.io/2019/04/11/go-channel/

在这里插入图片描述

Channel结构体

type hchan struct {
   
   
	qcount   uint           // total data in the queue
	dataqsiz uint           // size of the circular queue
	buf      unsafe.Pointer // points to an array of dataqsiz elements
	elemsize uint16
	closed   uint32
	elemtype *_type // element type
	sendx    uint   // send index
	recvx    uint   // receive index
	recvq    waitq  // list of recv waiters
	sendq    waitq  // list of send waiters

	// lock protects all fields in hchan, as well as several
	// fields in sudogs blocked on this channel.
	//
	// Do not change another G's status while holding this lock
	// (in particular, do not ready a G), as this can deadlock
	// with stack shrinking.
	lock mutex
}

我们可以看到,其中有一个buf空间,这个对应的是我们生成的有缓冲通道、无缓冲通道。recvqsendq对应的是waitq类型,其中主要存储的是发送、接受方的Goroutine。

waitq&&sudog

waitq


type waitq struct {
   
   
	first *sudog
	last  *sudog
}

sudog

// sudogs are allocated from a special pool. Use acquireSudog and
// releaseSudog to allocate and free them.
type sudog struct {
   
   
	// The following fields are protected by the hchan.lock of the
	// channel this sudog is blocking on. shrinkstack depends on
	// this for sudogs involved in channel ops.

	g *g

	next *sudog
	prev *sudog
	elem unsafe.Pointer // data element (may point to stack)

	// The following fields are never accessed concurrently.
	// For channels, waitlink is only accessed by g.
	// For semaphores, all fields (including the ones above)
	// are only accessed when holding a semaRoot lock.

	acquiretime int64
	releasetime int64
	ticket      uint32

	// isSelect indicates g is participating in a select, so
	// g.selectDone must be CAS'd to win the wake-up race.
	isSelect bool

	// success indicates whether communication over channel c
	// succeeded. It is true if the goroutine was awoken because a
	// value was delivered over channel c, and false if awoken
	// because c was closed.
	success bool

	parent   *sudog // semaRoot binary tree
	waitlink *sudog // g.waiting list or semaRoot
	waittail *sudog // semaRoot
	c        *hchan // channel
}

Channel工作流程

</

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值