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中进行内存的拷贝。


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

查看所有标签

猜你喜欢:

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

The Shallows

The Shallows

Nicholas Carr / W. W. Norton & Company / 2011-6-6 / USD 15.95

"Is Google making us stupid?" When Nicholas Carr posed that question, in a celebrated Atlantic Monthly cover story, he tapped into a well of anxiety about how the Internet is changing us. He also crys......一起来看看 《The Shallows》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试