1965年,美国科学家,企业家,英特尔公司创始人之一的戈登·摩尔撰写了一篇长达三页的论文,阐述了电子产品市场对集成电路的整合影响,并预测集成电路中元件数量每年至少增加一倍,而这个过程将持续至少十年。1975年,他修正了这一预测,指出集成电路中的元件数量每两年翻一番。 并持续到2012年左右。
一些公司预见摩尔定律预测的速度会放缓,开始研究增加计算能力的替代方法。 俗话说,必要性是创新之母,所以多核处理器就是这样诞生了。
这看起来像是解决摩尔定律边界问题的一种聪明方式,但是计算机科学家很快就发现自己面临着另一个定律的局限:以IBM360系列机的主要设计者阿姆达尔命名的阿姆达尔定律。
阿姆达尔定律指出,系统中对某一部件采用更快执行方式所能获得的系统性能改进程度,取决于这种执行方式被使用的频率,或所占总执行时间的比例。于是阿姆达尔致力于并行处理系统的研究。
例如,假设你正在编写一个基于GUI的程序:用户将看到一个界面,点击某些按钮,并发生一些事情。 这种类型的程序受到管道中一个非常大的连续部分的限制:人员交互。 无论为此程序提供多少内核,它总是受限于用户与界面进行交互的速度。
现在考虑一个不同的例子,计算pi的数字。多亏了spigot算法,我们可以很容易地将其划分为并行任务。在这种情况下,通过为程序提供更多的内核可以获得显著的收益,并且新问题变成了如何组合和存储结果。
阿姆达尔定律帮助我们理解这两个问题之间的差异,并帮助我们确定并行化是否是解决系统性能问题的正确方法。
对于这种类型的并行问题,建议编写可以水平扩展的应用程序。 这意味着可以使用程序的实例,在更多的CPU或机器上运行它,虽然这会导致系统的运行时间提高。 以这种方式构建程序非常简单,你可以将大块问题发送给应用程序的不同实例。
在21世纪初,当一种新的范式开始出现后,横向扩展变得容易得多:云计算。 尽管有迹象表明这个词早在20世纪70年代就已经被使用过了,但是21世纪初,这个概念真正在时代精神中扎根。 云计算意味着一种新的应用程序部署及扩展的规模和方法。 云计算替你配置物理设备,替你安装软件,替你进行维护,这意味着你可以访问庞大的资源池,这些资源池将按需提供到机器中供工作负载使用。 物理设备对使用者变得可有可无,并且配备了特别适合他们将要运行的程序的特性。 通常(但不总是)这些资源池被托管在其他公司拥有的数据中心中。
这种改变引发了一种新的思考。 突然之间,开发人员相对低成本的具备了大规模的计算能力,他们可以用它来解决大型问题。 解决方案现在可以轻松跨越许多机器甚至访问到全球。 云计算为以前那些只有技术巨头才有资格解决的问题提供了一套全新的低成本解决方案。
但云计算也带来了许多新的挑战。 调配资源,在设备之间进行通信以及汇总和存储结果都成为需要解决的问题。 但其中最困难的是弄清楚如何同时对代码进行建模。 部分解决方案可能在不同的机器上运行,这一情况加剧了建模问题时常见的一些问题。 这些问题很快就造就了新的解决方案,可伸缩网络。
网络通常希望能够通过添加更多应用程序实例来处理数十万(或更多)的同步工作负载,这使得滚动升级,弹性水平可伸缩体系结构和地理描述等成为必备属性,与此同时,这种解决方案还在编译和容错两方面引入了新的复杂度。
因此,我们发现,现代开发人员可能有点不知所措。2005年,ISO C++标准委员会主席,C++/CLI首席架构师Herb Sutter为Dobb博士撰写了一篇文章,标题为“免费午餐结束:软件并发的根本转向”。 标题贴切,文章有先见之明。 Sutter最后表示,“我们迫切需要一种更高层次的并发性编程模型,而非当前语言所能提供给我们的。”
如果想明白为什么Sutter有如此的“迫切感”,我们必须研究为什么并发很难得到正确的结果。
* * * * *
学识浅薄,错误在所难免。我是长风,欢迎来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运行时
- 任务调度