竞争避免:调度器的抢占和主动让出
【摘要】 1 简介Go 调度器是一个在用户态实现的、基于 G-P-M 模型 的自适应抢占式并发调度系统,让开发者几乎不用关心线程、锁、信号量,而只需专注于任务逻辑。配合通道可以高效实现并发任务。 2 示例 演示抢占调度与主动让出 func cpuIntensive(id int) { for i := 0; i < 10; i++ { fmt.Printf(...
1 简介
Go 调度器是一个在用户态实现的、基于 G-P-M 模型 的自适应抢占式并发调度系统,
让开发者几乎不用关心线程、锁、信号量,而只需专注于任务逻辑。配合通道可以高效实现并发任务。
2 示例 演示抢占调度与主动让出
func cpuIntensive(id int) {
for i := 0; i < 10; i++ {
fmt.Printf("CPU Task %d iteration %d\n", id, i)
if i == 5 {
runtime.Gosched() // 主动让出
}
}
}
func main() {
go cpuIntensive(1)
go cpuIntensive(2)
time.Sleep(time.Second)
}
说明:
两个 CPU 密集任务交替输出;
即使其中一个长时间运行,也会被抢占或主动让出执行权;
调度器保证了公平与响应性。
-
Go 调度器的优势
特性 描述 轻量级 创建一个 goroutine 只需几 KB 栈空间(线程通常需 MB 级) 用户态调度 无需系统调用切换上下文,效率高 工作窃取 自动负载均衡 抢占机制 避免“饿死”问题 CSP 模型配合 channel 任务协调更自然、安全
3 通道避免竞争
通道是 Go 中内置的并发机制,允许 goroutine 相互💬通信。
它们提供了一种在程序的不同部分之间传递数据的安全方法,防止数据损坏并确保线程安全🔒。这是一个例子:
以下代码显示了如何使用通道将数据从生产者 goroutine 传递到消费者 goroutine,演示了并发通信的强大功能。
package main
import "fmt"
func producer(ch chan int) {
for i := 1; i <= 5; i++ {
ch <- i
}
close(ch)
}
func consumer(ch chan int) {
for v := range ch {
fmt.Println(v)
}
}
func main() {
ch := make(chan int)
go producer(ch)
consumer(ch)
}
Go 的 通道(channel) 是其并发模型的核心,基于“通信顺序进程(CSP, Communicating Sequential Processes)”理论。
通道的核心思想是:不要通过共享内存来通信,而要通过通信来共享内存。
这与传统多线程环境中使用锁、信号量、共享内存等方式有本质区别。
- 通道典型使用场景(生产者-消费者模型)
示例 1:goroutine 之间的数据传递
package main
import (
"fmt"
"time"
)
func producer(ch chan int) {
for i := 1; i <= 5; i++ {
ch <- i // 发送数据
fmt.Println("Produced:", i)
time.Sleep(time.Millisecond * 200)
}
close(ch) // 通知消费者结束
}
func consumer(ch chan int) {
for num := range ch {
fmt.Println("Consumed:", num)
}
}
func main() {
ch := make(chan int)
go producer(ch)
consumer(ch)
}
说明:
producer 向通道发送数据;
consumer 从通道接收数据;
无需显式加锁或信号量,通道天然实现同步。
传统对比:
若用线程 + 共享队列,需要显式 mutex 保护;
用条件变量或信号量协调“数据可用”状态;
Go 通道简化了代码逻辑,避免竞争条件。
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)