就像我们在"Goroutines"章节中提到了,Go语言会帮你处理goroutine到系统线程上。它使用的算法被称为工作窃取策略(work stealing strategy)。这是什么意思?
首先,让我们看看在许多处理器之间共享工作的天然策略,有时称为公平调度。为了确保所有处理器的平均利用率,我们可以在所有可用处理器之间平均分配负载。想象一下,有n个处理器和x个任务需要执行。在公平调度策略中,每个处理器都会得到x/n个任务:
```
<Schedule Task 1>
<Schedule Task 2>
<Schedule Task 3>
<Schedule Task 4>
```
:-: ![](https://box.kancloud.cn/cd732c09b6cde622206c15d68017e78a_332x189.png)
不幸的是,这种方法存在问题。 如果你还记得“Goroutines”章节中我们提到Go使用fork-join模型来并发建模。在fork-join范例中,任务可能依赖于另一个,并且事实证明,在处理器之间分裂它们可能会导致其中一个处理器未充分利用。不仅如此,它还可能导致局部性缓存较差,因为在其他处理器上调度需要相同的数据任务。我们来看一个例子。
考虑一个程序,可以产生前面所述的工作分配。 如果第2项任务比第1项和第3项结合需要更长的时间,会发生什么?
:-: ![](https://box.kancloud.cn/4a87f72fa6430c6f7ab2cced47f61b37_584x119.jpg)
无论a和b之间的时间有多久,处理器一会闲置。
如果任务之间存在相互依存关系,如果分配给一个处理器的任务需要分配给另一个处理器的任务的结果,会发生什么情况? 例如,如果任务一依赖任务4呢?
![](https://box.kancloud.cn/988a6ddff4447aed35c9dec0193a1dd6_583x182.jpg)
在这种情况下,处理器1完全空闲,而任务2和4正在计算中。 虽然处理器1在任务1中被阻塞,处理器2在任务2中被占用,但处理器1可能已经在处理任务4以解除其自身阻塞。
* * * * *
学识浅薄,错误在所难免。我是长风,欢迎来Golang中国的群(211938256)就本书提出修改意见。
- 前序
- 谁适合读这本书
- 章节导读
- 在线资源
- 第一章 并发编程介绍
- 摩尔定律,可伸缩网络和我们所处的困境
- 为什么并发编程如此困难
- 数据竞争
- 原子性
- 内存访问同步
- 死锁,活锁和锁的饥饿问题
- 死锁
- 活锁
- 饥饿
- 并发安全性
- 优雅的面对复杂性
- 第二章 代码建模:序列化交互处理
- 并发与并行
- 什么是CSP
- CSP在Go中的衍生物
- Go的并发哲学
- 第三章 Go的并发构建模块
- Goroutines
- sync包
- WaitGroup
- Mutex和RWMutex
- Cond
- Once
- Pool
- Channels
- select语句
- GOMAXPROCS
- 结论
- 第四章 Go的并发编程范式
- 访问范围约束
- fo-select循环
- 防止Goroutine泄漏
- or-channel
- 错误处理
- 管道
- 构建管道的最佳实践
- 便利的生成器
- 扇入扇出
- or-done-channel
- tee-channel
- bridge-channel
- 队列
- context包
- 小结
- 第五章 可伸缩并发设计
- 错误传递
- 超时和取消
- 心跳
- 请求并发复制处理
- 速率限制
- Goroutines异常行为修复
- 本章小结
- 第六章 Goroutines和Go运行时
- 任务调度