Golang 之channel

栏目: Go · 发布时间: 6年前

内容简介:如果一直往channel中发送task,那么当channel满时,就会导致发送者(goroutine )的执行暂停。暂停的过程如下:一个线程持有一个P,P持有执行队列goroutine 阻塞,但是对应的OS的Thread不会阻塞,同时一个Thread管理的一组goroutine 不会引起线程的上下文切换

1.channel 的特性

  • goroutine-safe,多个 goroutine 可以同时访问一个 channel。
  • 多goroutine共享和通信
  • 先进先出FIFO
  • 可以导致 goroutine 的 block 和 unblock

2.channel 的结构

Golang 之channel

image.png

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
}

3.channel的发送和接收

Golang 之channel

image.png

  • G1是发送者(写入),G2是接收者(读取)
  • G1首先获得锁向taskCh发送task,将task放入环形队列进行排队
  • G2获取锁并从队列中拿到task,此处的task是内存的一个拷贝
  • 拷贝是安全的,因为channel通过mutex得到保护,没有共享内容,所有的内容都是拷贝的。

3.channel实现阻塞和非阻塞

如果一直往channel中发送task,那么当channel满时,就会导致发送者(goroutine )的执行暂停。暂停的过程如下:

  • 暂停发生在调度时
  • Goroutines 是用户态的线程(协程),是由runtime管理其生命周期,包括创建和管理。而不是操作系统,与操作系统层面对线程的调度开销相比,Goroutines 是属于上层调度更为轻量级
  • Go的调度器是M:N的调度模型,可以通过三层结构来描述。其中M代表OS的线程,N代表goroutine ,P代表调度的上下文

一个线程持有一个P,P持有执行队列

goroutine 阻塞,但是对应的OS的Thread不会阻塞,同时一个Thread管理的一组goroutine 不会引起线程的上下文切换

如何恢复G1的运行,但是其他的goroutine 一旦开始接收channel中的数据时(channel就不满了),此时需要恢复channel的发送者goroutine

4.goroutine 的暂停

Golang 之channel

pause.png

goroutine的暂停(例如上述的阻塞),chan会通知调度器来暂存goroutine,并将其状态从运行态修改成等待状态,同时从p中调度新的goroutine。

  • 这一点是很有优势的,一方面我们没有销毁线程,而是通过上下文切换来调度新的goroutine,注意此处的上下文不是线程的,而是goroutine级别的。这个代价会很小。
  • 一旦channel 不在满的时候,暂停的goroutine将会被恢复。

5.goroutine 的恢复

Golang 之channel

resume.png

  • 等待状态的goroutine 的机构中有一个指针指向等待的元素
  • 发送者(G1)在调用调度器之前,会给自己创建一个sudoG,用于在将来被恢复或者唤醒。
  • 当channel 不再满的时候,接收者(G2)会弹出sudoG,此时G1的状态将变为可执行状态,并由调度器再次调度(但不是立马)

6.直接发送

Golang 之channel

direct.png

当G1需要被恢复时,从理论上说,需要获取chan的锁,但是runtime此处有个优雅的设计,使其代价更小。runtime直接把G1复制到接收队列G2的栈中,不需要获取chan的锁。也不需要从chan中进行内存的拷贝。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

大数据经济

大数据经济

谢文 / 北京联合出版公司·后浪出版公司 / 2016-1 / 32.00元

中国互联网数朝元老、中国的“凯文·凯利”首度深度剖析大数据的大机会 大数据纳入中国国家行动方略,大数据产业起飞在即 陈彤、胡舒立、王巍鼎力推荐 ................... ※编辑推荐※ ★ 雅虎中国前总裁、中国互联网第一预言家——谢文,首部大数据力作。本书作者是中国互联网业第一代创业者,历任和讯网总裁、雅虎中国总裁、一起网CEO,亲身经历中国互联网发展全过......一起来看看 《大数据经济》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具