Golang中的gopark和goready


在Go语言的运行时系统中,gopark和goready是用于协调Goroutine调度的内部函数。它们通常由运行时系统自动管理,一般开发者不需要直接调用。以下是它们的核心作用和原理:


1. gopark:暂停当前Goroutine

  • 功能:
    gopark是一个运行时内部函数,用于将当前Goroutine设置为等待状态(如阻塞状态),并将其与当前线程分离。此时,调度器会回收当前线程,用于执行其他可运行的Goroutine。
  • 触发场景:
    当Goroutine需要等待某个事件时(如等待通道读写、定时器到期、I/O完成等),运行时系统会自动调用gopark。例如:
    ch := make(chan int)
    go func() {
        <-ch  // 接收数据时,若通道为空,当前Goroutine会被gopark挂起
    }()
    
  • 本质:
    释放当前线程资源,使调度器可以复用线程运行其他Goroutine。

2. goready:唤醒等待中的Goroutine

  • 功能:
    goready是配套的内部函数,用于将处于等待状态的Goroutine标记为可运行状态(放入调度器的运行队列),等待线程调度执行。
  • 触发场景:
    当等待的条件满足时,运行时系统会调用goready。例如,向通道发送数据时,若接收方Goroutine因等待被gopark挂起,发送操作会触发goready唤醒接收方:
    ch <- 42  // 发送数据时,若有接收方被挂起,会调用goready唤醒它
    
  • 本质:
    重新激活被挂起的Goroutine,使其能够继续执行。

协同工作机制

  • 挂起与回收:
    当一个Goroutine因条件未满足被gopark挂起时,运行时会将线程资源让给其他Goroutine,避免忙等待。
  • 条件满足时唤醒:
    当依赖的条件满足(如通道数据就绪、锁可用等),运行时通过goready将被挂起的Goroutine重新标记为可运行状态,加入调度队列等待执行。

注意事项

  • 内部函数:
    gopark和goready是runtime包的未导出函数,开发者无法直接调用(强行使用可能破坏调度逻辑)。
  • 调度透明性:
    Go的调度器自动处理挂起和唤醒,开发者只需关注并发语义(如select、channel、sync.Mutex等),无需操作底层函数。

示例场景:通道操作

ch := make(chan int)

// Goroutine 1:接收数据
go func() {
    val := <-ch  // 若通道空,被gopark挂起
    fmt.Println(val)
}()

// Goroutine 2:发送数据
go func() {
    ch <- 42     // 发送数据后,触发goready唤醒接收方
}()

发送数据时,若接收方Goroutine被挂起,运行时通过goready将其唤醒,使其返回运行队列并最终输出42。


总结

  • gopark:将Goroutine挂起并释放线程资源,优化并发效率。
  • goready:在条件满足时唤醒挂起的Goroutine,保障逻辑继续执行。
  • Go的调度器通过这两者的配合,实现了高效的协作式调度(M:N调度模型)。开发者只需基于高级抽象(如通道、锁)编写代码,底层细节由运行时系统自动处理。
posted @   guanyubo  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2024-02-26 C++ 刷题必备
2024-02-26 利用正则与状态机解析HTTP请求报文,实现处理静态资源的请求
2024-02-26 利用IO复用技术Epoll与线程池实现多线程的Reactor高并发模型
2024-02-26 C++14特性
2024-02-26 webserver服务器学习记录
2024-02-26 Linux内核工作原理
点击右上角即可分享
微信分享提示