goroutine、channel以及GMP模型的原理深度解析【万字分析】

本文详细探讨了Go语言中的并发机制,包括channel的底层数据结构、创建关闭及发送接受过程,goroutine的创建、运行、退出以及阻塞与唤醒状态,以及GMP模型的构成和调度原理。重点阐述了GMP模型中的G、M、P各自的角色和调度策略,如workstealing和handoff机制,以及抢占式调度的两种方式。
摘要由CSDN通过智能技术生成

前言

goroutine、channel以及GMP模型是学习golang绕不开的部分,之前学习golang的时候对这一块的理解不够深入,本文将深度分析并且总结他们的底层原理。

一、channel的底层原理

channel又称为管道,用于数据传递或数据共享,其本质是一个先进先出的队列,使用goroutine+channel进行数据通讯简单高效,同时也线程安全,多个goroutine可同时修改一个channel,不需要加锁。CSP(Communicating Sequential Process)并发模型,就是通过 goroutine 和 channel 来实现的)
channel有哪些状态:
**未初始化的状态,**只进行了声明,或者手动赋值为nil。

**active:**正常的channel,可读或者可写。

closed:已关闭,channel的值不是nil,关闭的状态的channel仍然可以读值(取值),但不能写值(会报panic: send on closed channel),nil状态的channel是不能close(panic: close of nil channel)的。如果关闭后的 channel 没有数据可读取时,将得到零值,即对应类型的默认值

1、底层数据结构

通过var声明或者make函数创建的channel变量是一个存储在函数栈帧上的指针,占用8个字节,指向堆上的hchan结构体
buf指向一个底层的循环数组,只有设置为有缓存的channel才会有buf
sendx和recvx分别指向底层循环数组的发送和接收元素位置的索引
sendq和recvq分别表示发送数据的被阻塞的goroutine和读取数据的goroutine,这两个都是一个双向链表结构
sendq和recvq 的结构为等待队列类型,sudog是对goroutine的一种封装 是双向链表,包含一个头结点和一个尾结点,每个节点是一个sudog结构体变量,记录哪个协程在等待,等待的是哪个channel,等待发送/接收的数据在哪里在这里插入图片描述

type hchan struct {
   
    qcount   uint           // channel中的元素个数
    dataqsiz uint           // channel中循环队列的长度
    buf      unsafe.Pointer // channel缓冲区数据指针
    elemsize uint16            // buffer中每个元素的大小
    closed   uint32            // channel是否已经关闭,0未关闭
    elemtype *_type // channel中的元素的类型
    sendx    uint   // channel发送操作处理到的位置
    recvx    uint   // channel接收操作处理到的位置
    recvq    waitq  //读等待队列 等待接收的sudog(sudog为封装了goroutine和数据的结构)队列由于缓冲区空间不足而阻塞的goroutine列表
    sendq    waitq  //写等待队列  等待发送的sudog队列,由于缓冲区空间不足而阻塞的goroutine列表

    lock mutex   // 一个轻量级锁
}

type waitq struct {
   
   first *sudog
   last  *sudog
}

type sudog struct {
   
    g *g
    next *sudog
    prev *sudog
    elem unsafe.Pointer 
    c        *hchan 
    ...
}




2、创建关闭

创建channel 有两种,一种是带缓冲的channel,一种是不带缓冲的channel

// 带缓冲
ch := make(chan int, 3)
// 不带缓冲
ch := make(chan int)

创建时的策略:
如果是无缓冲的 channel,会直接给 hchan 分配内存
如果是有缓冲的 channel,并且元素不包含指针,那么会为 hchan 和底层数组分配一段连续的地址
如果是有缓冲的 channel,并且元素包含指针,那么会为 hchan 和底层数组分别分配地址

关闭

3、发送接受

如果 channel 的读等待队列存在接收者goroutin

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值