package main
import (
"fmt"
)
func main() {
ch := make(chan int)
// 生产者匿名函数
go func() {
for i := 1; i <= 100; i++ {
ch <- i
}
close(ch)
}()
// 消费者匿名函数
go func() {
for num := range ch {
fmt.Println(num)
}
}()
// 防止主函数退出
select {}
}
协同工作原理
- 匿名函数与goroutine:通过
go
关键字将匿名函数包装成goroutine并发执行。生产者匿名函数负责生成数据,消费者匿名函数负责处理数据,二者并行运行。
- 匿名函数与channel:生产者匿名函数通过
ch <- i
将生成的数据发送到channel,消费者匿名函数通过for num := range ch
从channel接收数据。channel作为数据传递的桥梁,连接了生产者和消费者。
可能遇到的同步问题及解决办法
- 死锁:
- 问题:如果在生产者未向channel发送数据前,消费者先尝试从channel接收数据,或者在生产者未关闭channel的情况下主函数退出,都可能导致死锁。
- 解决办法:在生产者完成数据发送后,及时关闭channel,如上述代码中
close(ch)
。消费者使用for... range
循环从channel接收数据,这样当channel关闭时,循环会自动结束,避免死锁。
- 数据竞争:
- 问题:由于生产者和消费者是并发执行的,如果多个goroutine同时访问和修改共享资源(这里主要是channel),可能会引发数据竞争。
- 解决办法:在Go语言中,channel本身是线程安全的,所以在这个简单的生产者 - 消费者模型中,通过channel传递数据可以避免数据竞争问题。不需要额外的同步机制如互斥锁等来保护对channel的操作。