0

0

Go并发编程中channel怎么用_Go通道通信机制讲解

P粉602998670

P粉602998670

发布时间:2026-01-24 17:20:34

|

632人浏览过

|

来源于php中文网

原创

必须用make初始化channel才能发送或接收,nil channel操作会panic;无缓冲channel(make(chan T)或make(chan T, 0))同步阻塞,缓冲channel异步通信,容量不能为负。

go并发编程中channel怎么用_go通道通信机制讲解

channel 必须初始化才能发送或接收

声明一个 chan int 变量只是创建了 nil channel,对它做 sendrecv 会立即 panic:"panic: send on nil channel" 或 "fatal error: all goroutines are asleep - deadlock"。必须用 make 初始化,并指定缓冲区大小(0 表示无缓冲)。

常见写法:

ch := make(chan int)          // 无缓冲,同步通信
ch := make(chan string, 10)   // 缓冲容量为 10,异步通信

注意:make(chan T)make(chan T, 0) 效果相同,但后者语义更明确;缓冲区大小不能为负,传负数会 panic。

无缓冲 channel 的阻塞行为决定协程协作节奏

无缓冲 channel 的 操作是同步的:发送方会阻塞,直到有接收方就绪;接收方也一样。这天然适合“等待完成”“配对协作”场景,比如启动 goroutine 后等它结束:

done := make(chan bool)
go func() {
    // 做一些工作
    time.Sleep(100 * time.Millisecond)
    done <- true // 发送完成信号
}()
<-done // 主 goroutine 阻塞在此,直到收到信号

容易踩的坑:

  • 在同一个 goroutine 中对无缓冲 channel 先发后收(或先收后发),必然死锁
  • 多个 goroutine 同时向一个无缓冲 channel 发送,但只有一个接收者,其余发送者永久阻塞
  • 忘记关闭 channel 导致 range 无限等待(见下一条)

range channel 要求 channel 关闭,否则永远阻塞

for v := range ch 本质是持续接收,直到 channel 关闭且缓冲区为空。如果没人调用 close(ch),循环永远不会退出——即使所有发送者已退出,只要 channel 没关,range 就卡住。

koly.club
koly.club

一站式社群管理工具

下载

典型模式是“扇出-扇入”(fan-out/fan-in):

func fanIn(chs ...<-chan int) <-chan int {
    out := make(chan int)
    for _, ch := range chs {
        go func(c <-chan int) {
            for v := range c { // 这里依赖每个 c 被关闭
                out <- v
            }
        }(ch)
    }
    go func() {
        close(out) // 所有子 goroutine 结束后才关 out
    }()
    return out
}

关键点:

  • 只有 sender 应该调用 close(),receiver 调用会 panic
  • close() 只能调用一次,重复 close panic
  • 关闭后仍可接收(返回零值+ok=false),但不可再发送

select + timeout 是避免 channel 永久阻塞的标准解法

生产环境几乎不会让 goroutine 在 channel 上无限等待。用 select 配合 time.Aftercontext.WithTimeout 实现超时控制:

select {
case v := <-ch:
    fmt.Println("received:", v)
case <-time.After(2 * time.Second):
    fmt.Println("timeout")
}

注意:

  • select 默认随机选择一个就绪 case;所有 channel 都未就绪时,若含 default 则立即执行,否则阻塞
  • time.After 创建新 timer,频繁调用可能泄漏;高频率场景建议复用 time.NewTimer
  • 涉及 context 时,优先用 替代 time.After,便于主动取消

channel 的核心不是“传递数据”,而是“协调执行时机”。理解阻塞点在哪、谁负责关闭、如何设防超时,比记住语法更重要。

相关文章

编程速学教程(入门课程)
编程速学教程(入门课程)

编程怎么学习?编程怎么入门?编程在哪学?编程怎么学才快?不用担心,这里为大家提供了编程速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

188

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

291

2023.10.25

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

381

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

542

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

53

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

197

2025.08.29

Golang channel原理
Golang channel原理

本专题整合了Golang channel通信相关介绍,阅读专题下面的文章了解更多详细内容。

247

2025.11.14

golang channel相关教程
golang channel相关教程

本专题整合了golang处理channel相关教程,阅读专题下面的文章了解更多详细内容。

342

2025.11.17

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

24

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 4.1万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号