Go Channel 简介

280 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情

Go Channel

Go 核心的数据结构和 GoRoutine 之间的通信方式, Channel 是支撑 Go 语言高性能并发编程模型的重要结构。一个通道相当于一个先入先出的(FIFO) 的队列,也就是说通道中各个的元素值都是严格按照都顺序排列的。初始化一个通道时,需要用到 Go 内建函数 make, 同时还要确定通道的类型。

Channel

Channel 也称为管道。 Go 语言中最常说的一句话 “不要通过共享内存的方式进行通信,而是应该通过通信的方式共享内存”, 在 Java 中,多个线程传递数据一般都是通过共享内存的方式。

Goroutne 使用 Channel 传递数据, 一个会向 Channel 中发送数据,另外一个会从 Channel 中接收数据,他们两个能够独立运行,并不存在直接联系,但是能通过 Channel 完成通信。

在这里插入图片描述

Channel 读写规则 - 先入先出 FIFO

  • 先从 Channel 读取数据的 Goroutine 会先接收到数据。

  • 先向Channel 发送数据的 Goroutine 会得到先发送数据的权利

  • github.com/golang/go/i…

  • 发送方会向缓冲区写入数据, 然后唤醒接收方, 多个接收方会尝试从缓冲去中读取数据,如果没有读到数据,会重新休眠

  • 接收方会从缓冲去中读取数据,然后唤醒发送方, 发送方尝试向缓冲区中写入数据,如果缓冲区满,会重新陷入休眠

无锁管道 - channel

锁是一种常见的并发控制技术,一般会将锁分成乐观锁和悲观锁。即乐观并发控制和悲观并发控制, 无锁(lock-free)队列更准确的描述是使用乐观并发控制的队列,乐观并发控制也叫乐观锁。

Channel 在运行内部表示是 runtime.hchan, 结构中包含了用于包含成员变量的互斥锁,某种程度上说 channel 是一个用于同步和通信的有锁队列。使用互斥锁解决了程序中的线程竞争问题。

  • 同步 Channel - 不需要缓冲区,发送放回直接交给 Handoff 接收方
  • 异步 Channel - 基于环形缓冲的传统生产者消费者模型
  • chan struct{} 类型的异步 Channel - Struct{} 类型不占用内存空间,不需要事先缓冲区和直接发送 Handoff

数据结构

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
}

参考资料