Go-知识并发控制Channel
channel 作为协程间通信的类型,用来在协程间传递信息是基本能力,而通过灵活的使用 channel ,可以实现各种各样复杂的并发控制。
Go-知识并发控制Channel
文章信息
- 原文链接:https://jiayq.blog.csdn.net/article/details/138972958
- 发布时间:2024-05-16 19:38:45
- 阅读量:588
- 分类:Golang专栏收录该内容, 订阅专栏
- 标签:#golang, #go, #go 并发管理, #chan, #channel
摘要
文章浏览阅读588次,点赞5次,收藏7次。channel 作为协程间通信的类型,用来在协程间传递信息是基本能力,而通过灵活的使用 channel ,可以实现各种各样复杂的并发控制。
Go-知识并发控制Channel
- 1. 无缓冲 chan 实现 并发控制
- 2. 有缓冲 chan 实现 并发控制
- 3. 总结
薅羊毛:Baidu Comate,200积分换20元京东E卡
给你分享一个AI编码助手——百度Comate!扫码参与抽红包活动,520宠粉!送京东卡!https://comate.baidu.com/zh/shopping?inviteCode=y21fpcef
薅羊毛:Baidu Comate,200积分换20元京东E卡
channel 一般用于协程之间的通信,不过channel也可以用于并发控制。 比如主协程启动N个子协程,主协程等待所有子协程退出后再继续后续流程,这种并发控制的场景,channel也可以实现。
channel 的用法: Go 知识chan
1. 无缓冲 chan 实现 并发控制
假设要在主协程中创建10个子协程,主协程等待子协程执行完成后主协程在退出。
Go 知识for-range
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
func TestCc(t *testing.T) {
// 定义子协程个数
sum := 10
// 创建10个 chan 用于通信
chs := make([]chan struct{}, sum)
for i := 0; i < sum; i++ {
// 创建 chan
ch := make(chan struct{})
chs[i] = ch
// 因为在 子协程中用到了 chan 和 index ,所以使用临时变量拷贝一下, for - range
// 更多细节: https://jiayq.blog.csdn.net/article/details/135886263
ti := i
go func() {
// 子协程打印消息
name := fmt.Sprintf("goroutine %d", ti)
fmt.Println(name, "start")
// 子协程睡眠模拟耗时逻辑
time.Sleep(3 * time.Second)
fmt.Println(name, "end")
// 发送子协程完成和退出信号
ch <- struct{}{}
// 关闭资源
close(ch)
}()
}
// 在主协程中读取子协程的退出信号,阻塞从 chan 中读取数据
for _, ch := range chs {
<-ch
}
fmt.Println("all goroutine done")
}
和预期一致。
2. 有缓冲 chan 实现 并发控制
还是和1相同的逻辑,区别在于上面是一个子协程就有1个 chan ,假设有1w的子协程,就需要创建1w的chan。
而有缓冲的 chan 则只需要一个即可:
Go-知识协程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
func TestCc1(t *testing.T) {
// 主协程中创建10个子协程
sum := 10
// 创建 带有 10 个 缓冲空间的 chan
// 缓冲空间的大小和需要管理的子协程的大小应该相同,否则子协程如果执行比较快,就会因为缓冲满而阻塞
// 其实子协程因为缓冲满阻塞,也没有关系,依赖 go 的高效 调度,当出现因为 chan 阻塞时,长时间无法得到资源,
// 就会让 绑定 G 的 P 脱离 M , 等到 chan 有空间了在继续执行
// 更多细节: https://jiayq.blog.csdn.net/article/details/137087910
ch := make(chan struct{}, sum)
for i := 0; i < sum; i++ {
// 闭包使用
ti := i
go func() {
name := fmt.Sprintf("goroutine %d", ti)
fmt.Println(name, "start")
time.Sleep(3 * time.Second)
fmt.Println(name, "end")
ch <- struct{}{}
}()
}
for i := 0; i < sum; i++ {
<-ch
}
close(ch)
fmt.Println("all goroutine done")
}
3. 总结
channel 作为协程间通信的类型,用来在协程间传递信息是基本能力,而通过灵活的使用 channel ,可以实现各种各样复杂的并发控制。
本文由作者按照 CC BY 4.0 进行授权


