到目前为止,我描绘了一个非常严酷的场景。 并发在计算机科学中当然是一个困难的领域,但我希望你不要失去希望:这些问题不是无解的,使用Go的并发原语,可以更安全,更清晰地表达并发算法。 我们讨论的运行时长和沟通困难并不是Go能够完全解决的,但它们确实变得更加容易处理了。在这里,我们花一点时间来探索Go的并发原语,以助于更容易地对问题域进行建模,并更清楚地表达算法。
Go的运行时完成了大部分繁重的工作,并为Go的大部分并发优势提供了基础。详细部分我们放到第6章再讲,但现在让我们讨论下它是如何让人生变得轻松的。
我们先看看Go的并发,低延迟,自动执行垃圾收集器(GC)。开发者经常讨论GC是否是语言中必备的东西。批评者认为,GC阻止任何需要实时性能或确定性能特征的问题领域的工作——暂停程序中的所有活动来清理垃圾简直是不可接受的。但Go的GC所做的出色工作大大减少了开发者的心智负担。从Go 1.8开始,垃圾收集暂停一般在10到100微秒之间。
这对你有什么帮助? 内存管理可能是计算机科学领域的另一个难题,如果与并发性结合使用,编写正确的代码变得非常困难。如果大多数开发人员不需要担心低至10微秒的暂停时间,那么Go通过不强迫你管理内存而更容易使用并发程序,更不用说跨并发进程了。
Go的运行时也会自动处理并发操作到操作系统线程上。这么说有些笼统,我们将在第三章的“Goroutines”一节中确切地说明这意味着什么。为了理解这对开发者的帮助,你需要知道的一点是它允许开发者直接将并发问题映射到结构体,而不是处理启动和管理线程的细节,并在可用线程间均匀映射逻辑。
例如,假设你编写了一个Web服务器,并且你希望每个连接都可以与其他连接同时处理。 在某些语言中,在Web服务器开始接受连接之前,你可能必须创建一个线程集合(通常称为线程池),然后将传入连接映射到线程。 然后,在你创建的每个线程中,你需要循环该线程上的所有连接,以确保它们都获得了一些CPU时间。 另外,你必须编写你的连接处理逻辑,使它可以与其他连接公平地共享。
相比之下,在Go中你可以编写一个函数,然后用go关键字预先调用它。 运行时会处理我们自动调用的所有内容! 当你正在经历设计程序的过程时,你认为在哪种模型下你更有可能达到预期的并发效果? 你认为哪个更可能是正确的?
Go的并发原语也使得解决更大的问题变得更容易。 正如我们将在第三章的“Channels”部分中看到的,Go的channel原语为并发进程之间的通信提供了可组合,并发安全的方式。
我已经掩盖了大部分细节,但我想给阐述一些关于Go如何在程序中处理并发,以帮助你以清晰和高效的方式解决问题。 这将是下一张的内容。 如果渴望立刻开始讨论代码,你可能会想转到第三章。
* * * * *
学识浅薄,错误在所难免。我是长风,欢迎来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运行时
- 任务调度