📚 原创系列: “Go语言学习系列”
🔄 转载说明: 本文最初发布于"Gopher部落"微信公众号,经原作者授权转载。
🔗 关注原创: 欢迎扫描文末二维码,关注"Gopher部落"微信公众号获取第一手Go技术文章。
📑 Go语言学习系列导航
🚀 第三阶段:进阶篇本文是【Go语言学习系列】的第29篇,当前位于第三阶段(进阶篇)
- 并发编程(一):goroutine基础
- 并发编程(二):channel基础 👈 当前位置
- 并发编程(三):select语句
- 并发编程(四):sync包
- 并发编程(五):并发模式
- 并发编程(六):原子操作与内存模型
- 数据库编程(一):SQL接口
- 数据库编程(二):ORM技术
- Web开发(一):路由与中间件
- Web开发(二):模板与静态资源
- Web开发(三):API开发
- Web开发(四):认证与授权
- Web开发(五):WebSocket
- 微服务(一):基础概念
- 微服务(二):gRPC入门
- 日志与监控
- 第三阶段项目实战:微服务聊天应用
📖 文章导读
在本文中,您将了解:
- channel的基本概念与作用
- 无缓冲与缓冲channel的区别与适用场景
- channel的发送与接收操作
- 如何正确关闭channel
- 使用channel进行goroutine间通信的最佳实践
- 常见的channel错误与陷阱
本文是掌握Go并发编程的关键一步,channel与goroutine共同构成了Go语言并发模型的核心。通过理解channel的工作原理,您将能够设计出更加高效、安全的并发程序。

并发编程(二):channel基础
在上一篇文章中,我们介绍了Go语言并发编程的核心机制之一——goroutine。而今天,我们将深入探讨Go并发模型的另一个核心组件:channel(通道)。channel是goroutine之间进行通信和同步的主要机制,它实现了CSP(通信顺序进程)模型中"通过通信来共享内存"的理念。
一、channel概念
1.1 什么是channel
channel是Go语言提供的一种数据结构,它像一个管道,可以在不同的goroutine之间安全地传递数据。channel有以下特点:
- 类型安全:每个channel只能传递指定类型的数据
- 并发安全:channel的操作是原子的,不需要额外的锁
- FIFO顺序:数据按照先进先出的顺序从channel中读取
- 阻塞机制:可以用于goroutine之间的同步
从本质上讲,channel是一个数据结构,内部包含一个缓冲区、一个互斥锁以及两个等待队列(发送者队列和接收者队列)。
1.2 为什么需要channel
在并发编程中,我们通常需要解决以下问题:
- 数据共享:多个goroutine需要安全地共享数据
- 工作分发:将任务分配给多个worker goroutine
- 信号通知:发送事件信号(如完成、取消等)
- 同步控制:协调不同goroutine的执行顺序
传统的共享内存并发模型通常使用锁来解决这些问题,但锁机制容易导致复杂性增加、死锁和性能问题。channel提供了一种更简洁、更符合Go语言哲学的方案。
1.3 channel类型
在Go中,channel类型表示为chan T,其中T是channel中传递的数据类型。channel有三种基本类型:
-
双向channel:可以发送和接收数据
var ch chan int // 双向channel,可发送和接收int -
只发送channel:只能发送数据,不能接收
var sendCh chan<- int // 只发送channel -
只接收channel:只能接收数据,不能发送
var recvCh <-chan int // 只接收channel
类型转换关系:
- 双向channel可以转换为单向channel,但反之不行
- 这种转换通常用于函数参数,限制函数对channel的操作
func send(ch chan<- int) {
ch <- 42 // 只能发送
// <-ch // 编译错误:不能从只发送channel接收
}
func receive(ch <-chan int) {
v := <-ch // 只能接收
// ch <- 42 // 编译错误:不能向只接收channel发送
}
func main() {
ch := make(chan int) // 双向channel
go send(ch) // 可以将双向channel传给只发送channel参数
go receive(ch) // 可以将双向channel传给只接收channel参数
}
二、无缓冲与缓冲channel
Go语言中的channel分为两种:无缓冲channel和缓冲channel,它们有着不同的行为特性。
2.1 无缓冲channel
无缓冲channel没有存储容量,发送操作必须等待接收操作,反之亦然。因此,无缓冲channel提供了goroutine之间的同步保证。
创建方式:
ch := make(chan int) // 无缓冲channel
// 或
ch := make(chan int, 0) // 显式指定缓冲大小为0
行为特点:
- 发送操作会阻塞,直到有另一个goroutine执行接收操作
- 接收操作会阻塞,直到有另一个goroutine执行发送操作
- 发送和接收操作同时就绪时,数据交换才会发生
示例:
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan string) // 无缓冲channel
go func() {
fmt.Println("Goroutine starts...")
time.Sleep(2 * time.Second)
fmt.Println("Goroutine sending data...")
ch <- "Hello from goroutine!" // 发送数据到channel
fmt.Println(

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



