不记录,等于没读。
这里是我阅读《程序员修炼之道》这本书的记录和思考。
并发和并行代码曾经是很新奇的玩意,但现在已经是标配。
并发
:Concurrency,指的是两个或更多个代码段在执行过程中表现得像是在同时运行一样。
并行
:Parallelism,指的是两个或更多个代码段的确是在同一时刻一起运行(需要硬件多核支持)。
打破时域耦合
时域耦合
指的是时间。如果代码给几件事情强加一个顺序进来,而这个顺序对解决手头问题而言并非需要,就会发生 时域耦合
。如果想保持灵活性就不要这样。
时间
对我们来说有两个重要的方面:并发性
以及 次序
(事情在时间轴上的相对位置)。
时域耦合——在时间范畴上产生耦合:A 方法必须在 B 方法之前调用;一次只能运行一个报告;在按钮按下前必须等屏幕先重绘……这些方法不太灵活,也不太符合现实。
我们需要考虑并发性,并且考虑对时间依赖或顺序依赖解耦。利用 活动图
之类的工具来清理工作流们可以让我们知道哪些事情可以同时进行,哪些必须按照严格的顺序发生。这是设计工作的一部分。
针对并发做设计所追求的东西是:找到那些耗时的活动,从中找出等待的操作,比如查询数据库、等待用户输入,在这些等待的间隙,去做一些更有意义的事情。
识别出哪些地方可以从并发和并行中受益知识第一步,接下来到了棘手的部分:如何安全地实现并发和并行。
共享状态是不正确的状态
你坐在最喜欢的餐厅。吃完主菜,问服务员还有没有苹果派。他回头看了看,看到陈列柜里有一个,说“有的”。你点了它,心满意足地长出一口气。
与此同时,在餐厅的另一边,另一位顾客问另一个服务员同样的问题。她也看了看,确认有一个,然后顾客点了单。
总会有一个顾客会失望的。
问题出在共享状态。餐馆里的每一位服务员都查看了陈列柜,却没有考虑到其他服务员。这两个服务员在并行操作,他们对苹果派的数量的获取和更新,均不是 原子操作
。
信号量
和其它形式的 互斥量
可以让行为具有原子操作。简而言之,它们是一个在同一时间只能让一个人持有的东西。
比如可以在苹果派的陈列柜上放一个塑料小妖精(充当一个信号量)。任何服务员在卖苹果派之前,必须先把小妖精抓在手里,直到把苹果派送到顾客桌子上才可以把小妖精放回原处。
这种方法可行,但也存在一些问题,就是所有服务员都必须严格遵循纪律才行得通。如果一个服务员故意或忘记使用小妖精,那么我们又会陷入混乱。这是因为将保护陈列柜访问权的责任委托给了使用它的人。
所以我们得换一种方法,让资源具备 事务性
。也就是对该资源的操作具有原子性。比如服务员在查看苹果派数量时,如果有,则直接获取一个苹果派,顾客如果点单,则将这个苹果派给顾客;如果顾客不想要了,再把苹果派放回陈列柜。
如果顾客既要苹果派又要冰淇淋,这就涉及更复杂的多资源分配。多资源分配处理不好就会引发死锁。书中推荐的方法是将多个资源放入一个模块,要么成功分配所有资源,要么分配失败。
任何时候,只要两个或多个代码块持有对同一个可变数据块的引用,就已经共享了状态。
Linux 环境中,当前目录
也是共享资源,在线程之间共享。任何修改当前目录的操作,都要注意。
随机故障通常是并发问题。
Actor 模型
在共享资源环境中实现并发非常难,Actor 模型可以简化并发设计。
Actor 模型应该翻译成什么,书中翻译成“角色模式”,它和现实中的演员角色如何对应,我查了很久的资料,最后还是不知道。
Actor 模型是一个抽象模型,用于并发运算,并不绑定任何编程语言。在上一节,主要内容是讲述了 共享状态
会带来无穷的麻烦,而本节,则推荐使用 Actor 模型来管理并发状态,从而简化并发设计。
Actor 模型的推崇的哲学是:一切皆 Actor。
根据书中描述,Actor 具有以下特征:
- 一个 Actor 是一个进程,即一个独立的虚拟处理单元。
- 具有自己的本地私有
状态
(state)。 - 每个 Actor 都有一个
信箱
(mailbox) 。 - 当消息出现在信箱中且 Actor 处于空闲状态时,Actor 被激活并开始处理消息。
- Actor 会循环处理邮箱中的信息,直到邮箱为空,然后 Actor 进入休眠。
在处理消息的过程中,一个 Actor 可以有以下动作:
- 可以创建其它 Actor。
- 可以向它认识的 Actor 发送消息 ,并创建一个新状态,该状态将在处理下一条消息时成为当前状态。
使用 Actor 需要满足以下纪律:
- 没有一件事是可控的。不能假设它是有序的。
- 系统中
唯一
的状态,保存在消息和每个 Actor 的本地状态中。本地状态在 Actor 之外无法被读取。 - 所有消息都是单向的,没有回应这个概念。如果希望 Actor 能返回一个回应消息,则需要在发送给 Actor 的消息中包含自己的邮箱地址,然后由 Actor 将回应作为另一条消息发送到该邮箱。
- Actor 一次只会处理一条消息。
并发实在是太容易出问题了,所以就出现了 Actor 模型,用一系列规范来简化并发处理,它是在数学上可证明的(见 Gul Agha 的 1985 年学位论文)。
每一份打赏,都是对创作者劳动的肯定与回报。!