同步算法
-
保守同步(Conservative)避免违反本地因果约束(等到安全时再进行)
- 使用空消息避免死锁(Chandy/Misra/Bryant)
- 死锁检测与恢复
- 同步算法(例如,按“轮次”执行)
-
乐观同步(Optimistic)允许本地因果关系的违反发生,但在运行时检测并通过回滚机制恢复
- 时间扭曲(Jefferson)
- 众多其他方法
保守方法介绍
-
死锁避免
- 使用空消息来避免死锁
-
死锁检测与恢复
- 一旦发生死锁,采取措施进行恢复/打破死锁
Chandy/Misra/Bryant“空消息”算法 假设:
- 逻辑处理单元(LPs)交换时间戳事件(消息)
- 静态网络拓扑,不动态创建LPs
- 每个链接上发送的消息都按时间戳顺序发送
- 网络提供可靠的传输,保持顺序
观察:以上假设意味着接收到的最后一条消息的时间戳是该链接后续消息时间戳的下限(LBTS)
目标:确保LP按时间戳顺序处理事件
一个简单的保守算法
● 算法A(每个LP执行):
● 目标:确保按时间戳顺序处理事件:
● WHILE(模拟未结束) 等
- 待每个FIFO至少包含一条消息
- 从其FIFO中移除时间戳最小的事件
- 处理该事件
● END-LOOP
观察:算法A容易发生死锁!
一系列LP形成,其中每个LP都在等待循环中的下一个LP。 没有LP可以前进;模拟陷入死锁。
使用空消息避免死锁
通过让每个LP发送“空消息”来打破死锁,表明其未来可能发送的消息的时间戳下限。
假设主机之间的最小延迟为3个模拟时间单位
- H3最初在时间5
- H3发送时间戳为8的空消息到H2
- H2发送时间戳为11的空消息到H1
- H1现在可以处理时间戳为7的消息
● 空消息算法(每个LP执行):
● 目标:确保按时间戳顺序处理事件并避免死锁
● WHILE(模拟未结束)
- 等待每个FIFO至少包含一条消息
- 从其FIFO中移除时间戳最小的事件
- 处理该事件
- 向相邻LP发送空消息,时间戳表示发送到该LP的未来消息的下限(当前时间加上前瞻)
● END-LOOP
空消息算法依赖于一个“前瞻”(最小延迟)。
前瞻 - 如果一个LP在模拟时间T只能安排新事件的时间戳至少为T + L,则L被称为该逻辑处理单元的前瞻。
保守方法
● 死锁避免算法要求:
- 链接必须静态指定。
- 通过链接发送的时间戳消息必须非递减,以确保事件按递增时间顺序执行。
- 每个链接都有一个关联的时钟。时钟时间设置为队列头部的最后收到的消息的时间戳。
- 过程依次查看每个链接并选择时间戳最小的消息。如果所选队列为空,则过程阻塞。发生死锁!
- 发送空消息以避免死锁。来自LPA到LPB的空消息(Tnull)是LPA的承诺,即它不会向LPB发送时间戳小于Tnull的消息。
使用空消息避免死锁(变体)
●空消息算法(每个LP执行):
●目标:确保按时间戳顺序处理事件并避免死锁
●WHILE(模拟未结束)
- 等待每个FIFO至少包含一条消息
- 从其FIFO中移除时间戳最小的事件
- 处理该事件
- 向相邻LP发送空消息,时间戳表示发送到该LP的未来消息的下限(当前时间加上前瞻)
●END-LOOP
变体:当FIFO变空时,LP请求空消息
- 更少的空消息
- 获取时间戳信息的延迟
活锁可能发生!
假设LPs之间的最小延迟为零!
活锁:无尽的空消息循环,没有LP可以推进其模拟时间
不能存在一个循环,其中每个LP在循环中收到时间戳为T的消息,导致向循环中的下一个LP发送时间戳为T的新消息(零前瞻循环)
前瞻
空消息算法依赖于被称为前瞻的“预测”能力
- “H3在模拟时间5,LPs之间的最小过境时间为3,所以H3发送的下一条消息的时间戳至少为8”
前瞻是LP行为的一个限制
- 链接前瞻:如果一个LP在模拟时间T,出站链接有前瞻Li,则该链接上发送的任何消息的时间戳必须至少为T+Li
- LP前瞻:如果一个LP在模拟时间T,并有前瞻L,则该LP发送的任何消息的时间戳必须至少为T+L----->等同于每个出站链接的前瞻相同的链接前瞻
程序能够利用前瞻的程度对性能至关重要
前瞻和模拟模型
- 可以从被模拟系统中的物理限制派生,例如一实体影响另一实体的最小模拟时间(例如,从坦克发射的武器需要L单位时间到达另一坦克,或坦克的最大速度对其影响另一实体的时间设定下限)
- 可以从模拟实体的特征派生,例如不可抢占行为(例如,一辆坦克以每小时30英里的速度向北行驶,联盟模型中没有任何东西可以在接下来的10分钟内改变其行为,所以坦克模拟器可以立即生成直到“本地时钟+10分钟”的所有输出)
- 可以从对时间不准容忍度派生(例如,用户无法感知100毫秒的时间差异,因此消息可以被时间戳标记为未来100毫秒)
- 模拟可能能够预计其与另一模拟的下次互动时间(例如,如果下次互动时间是随机的,预先抽样随机数生成器以确定下次互动的时间)
观察:时间步进模拟隐含地使用前瞻;当前时间步中的事件被认为是独立的(可以并行处理),新事件为下一时间步或之后生成
每个使用逻辑时间的LP A声明一个前瞻值L;由LP生成的任何事件的时间戳必须≥LTA+L。
- 前瞻在几乎所有保守同步协议中都被使用
- 对于并行处理不同时间戳的事件至关重要
- 前瞻对于允许并行处理不同时间戳的事件(除非使用乐观事件处理)是必要的
更改前瞻值
增加前瞻
- 没有问题;前瞻可以立即更改
减少前瞻
- 必须遵守之前的时间戳保证
- 前瞻不能立即减少:
如果一个LP在模拟时间10,前瞻为5,它已承诺后续消息的时间戳至少为15
如果前瞻立即设为1,则它可以生成时间戳为11的消息
- 前瞻只能在LP推进k个模拟时间单位后减少k个单位
例子:减少前瞻
- H2: 模拟时间=10,前瞻=5
- 发送到链接的未来消息必须有时间戳≥15
- H2: 请求将其前瞻减少到1
预防前瞻值漂移:下一事件时间信息
观察:如果所有LP被阻塞,最小时间戳的事件是安全的处理对象
- 通过允许同步算法立即推进到下一事件的(全局)时间来避免前瞻值漂移
- 同步算法必须知道LP下一事件的时间戳
- 每个LP保证一个逻辑时间T,即如果没有额外的事件以TS < T传递给LP,那么该LP产生的所有后续消息的时间戳至少为T+L(L=前瞻)
时间戳的下限(LBTS)
无空消息,假设任何LP都可以向任何其他LP发送消息
当LP阻塞时,计算其可能稍后接收的消息的时间戳的下限(LBTS);时间戳小于LBTS的消息是安全的处理对象
给定计算的快照,LBTS是以下项中的最小值:
- 任何在途消息的时间戳(已发送但尚未接收)
- 未阻塞的LPs:当前模拟时间 + 前瞻
- 阻塞的LPs:下一事件时间 + 前瞻
可使用分布式快照算法(Mattern)异步计算 LBTS
- 切点:将进程的计算划分为过去和未来的瞬间
- 切:每个进程的切点集合
- 切消息:在过去发送并在未来接收的消息
- 一致切:切 + 所有切消息
- 切值:(1)每个切点的本地最小值和(2)切消息的时间戳之间的最小值;非切消息可以忽略
可以证明LBTS = 切值
发起者广播启动LBTS计算消息给所有LPs 每个LP设置切点,向发起者报告本地最小值 考虑在途(切)消息
● 识别在途消息,将时间戳包括在最小值计算中
- 为每个LP(颜色随每个切点改变)着色;消息颜色 = 发送者颜色
- 如果接收消息的颜色与接收者之前的颜色相同,则该消息是在途的
- 当收到在途消息时向发起者报告时间戳
● 检测所有在途消息是否已接收
- 对于每种颜色,LPi保持已发送(Sendi)和已接收(Receivei)消息的计数器
- 在切点时,将计数器发送给发起者:#在途消息 = Σ(Sendi - Receivei)
- 发起者检测终止(所有在途消息已接收),广播全局最小值
同步算法
● DO WHILE(未处理事件仍然存在)
- 屏障同步;清空网络中的所有消息
- LBTS = min(Ni + LAi);Ni = LPi中下一个事件的时间;LAi = LPi的前瞻
- S = 时间戳≤LBTS的事件集合
- 处理S中的事件
● endDO
由Lubachevsky、Ayani、Chandy/Sherman、Nicol提出的变体
保守同步总结
- 每个LP必须按时间戳顺序处理事件
- 必须计算LP可能接收到的未来消息的时间戳的下限(LBTS),以确定哪些事件是安全的处理对象
- 第一代算法:基于LPs当前模拟时间和前瞻的LBTS计算
- 空消息
- 易于前瞻值漂移
- 不允许零前瞻周期
- 第二代算法:还考虑下一事件时间来避免前瞻值漂移
- 其他信息,例如LP拓扑,可以被利用
- 前瞻对于实现事件的并行处理、良好性能至关重要
- 必须编写程序以利用前瞻
缺点
- 不能充分利用模拟中可用的并行性,因为它们必须防范“最坏情况”
- 前瞻对于实现良好性能至关重要
- 不够健壮:微小的改变(前瞻)可能会极大地影响性能
- 编写具有良好前瞻的模拟程序可能非常困难或不可能,并且可能导致难以维护的代码
- 许多现有的保守技术需要静态配置:不能动态创建新的进程,逻辑处理单元之间的互连必须静态定义。
优点
- 许多应用报告良好性能(排队网络、通信网络、战争游戏)
- 相对容易实现
- 适合“联合”自治模拟,前提是有良好的前瞻
乐观方法
- 无需确定何时安全进行;确定发生错误时,并调用恢复程序。
- 利用更多的并行性(投机并行),并且可以轻松容纳动态创建的逻辑处理单元。
- 基于虚拟时间范式的时间扭曲机制是最著名的乐观协议。
时间扭曲算法(Jefferson)
假设:
- 逻辑处理单元(LPs)交换时间戳事件(消息)
- 动态网络拓扑,动态创建LPs是可行的
- 每个链接上发送的消息不需要按时间戳顺序发送
- 网络提供可靠传输,但不需要保持顺序
基本思想:
- 处理事件时不用担心稍后到达的消息
- 检测顺序错误的执行,通过回滚恢复
- 虚拟时间与模拟时间同义。当收到的事件消息包含的时间戳小于进程时钟的时间戳(即最后处理的消息的时间戳)时,将检测到因果错误。导致回滚的事件被称为滞后者。调用恢复以撤销所有被滞后者接收的进程过早处理的事件的影响。
- 在时间扭曲中,所有未处理事件消息中最小的时间戳被称为全局虚拟时间(GVT)。时间戳小于GVT的任何事件都不会被回滚。
- 一个事件可能需要回滚的两个操作是:它可能修改逻辑处理单元的状态,和/或向其他处理单元发送事件消息。
- 为了能够回滚,定期保存进程的状态(状态向量),并在回滚时恢复旧状态。
- 积极消息指的是对应于模拟器事件的消息。通过发送反消息(或负消息)来取消积极消息的效果,使所有错误计算的效果得以取消。当一个进程接收到一个与它已处理的积极消息对应的反消息时,该进程将被回滚以撤销即将被销毁的积极消息的处理效果。这个过程会递归重复,直到达到正确的模拟状态。
- 这被称为积极取消——每当一个进程回滚到时间T时,立即为任何之前发送的时间戳大于T的积极消息发送反消息。
乐观协议
相对于保守机制提供多个优点:
- 更充分地利用并行性
- 对前瞻信息的依赖较少--->同步协议更透明---->更容易开发和维护应用代码
- 注意:虽然前瞻不是必需的,但它通常可以提高性能,因此在可用时应该利用
潜在的缺点
- 需要保存状态以启用回滚
- 可能显著降低性能
- 可能难以实施
- 可能存在过度回滚,回滚“抖动”
- 内存需求可能很大
时间扭曲(Jefferson)回滚
每个LP:像顺序模拟器一样按时间戳顺序处理事件,除了:(1)不丢弃已处理事件和(2)添加回滚机制
添加回滚:
- 在LP的过去到达的消息启动回滚
- 要回滚事件计算,我们必须撤销:
- 事件执行的状态变量更改;解决方案:检查点状态或使用增量状态保存(状态队列)
- 消息发送; 解决方案:反信息和信息湮灭(输出队列)
- 用于取消之前发送的消息
- 每个LP发送的每个积极消息都有一个对应的反消息
- 反消息与积极消息相同,除了有一个符号位
- 当反消息和它匹配的积极消息在同一个队列中相遇时,两者相互抵消(类似于物质和反物质)
- 为了撤销之前发送的(积极的)消息的影响,LP只需发送相应的反消息
- 消息发送:在发送消息的同时,在发送LP称为输出队列的数据结构中留下相应反消息的副本
全局虚拟时间和化石收集
● 需要一种机制来:
- 回收内存资源(例如,旧状态和事件)
- 执行不可撤销的操作(例如,I/O)
● 观察:需要未来可能发生的任何回滚的时间戳的下限。
● 全局虚拟时间(GVT)定义为系统中任何未处理(或部分处理)的消息或反消息的最小时间戳。GVT为任何未来回滚提供了时间戳的下限。
- 可以回收早于GVT的事件和状态向量的存储(除了一个状态向量)
- 可以执行时间戳小于GVT的I/O操作。
- GVT算法与保守同步中的LBTS算法类似
● 观察:与GVT对应的计算不会被回滚,保证向前进展。
回滚优化:
(1)懒取消
这种方法处理消息。进程不会立即为任何回滚计算发送它们的反消息。相反,它们等待看看重新执行的计算是否重新生成相同的消息;如果重新创建了相同的消息,则无需取消该消息。
积极取消的性能不会优于关键路径执行时间,懒取消的性能可能根据应用的细节和可用处理器的数量任意地更好或更差。实证证据表明,懒取消在实践中往往表现得同样好或者比积极取消更好。
(2)懒惰重评估
这种方法处理状态向量而不是消息。如果处理滞后事件前后进程的状态相同,则不需要回滚。这需要比较状态向量来确定状态是否发生了变化。
(3)乐观时间窗口
使用时间窗口来防止错误计算过多地传播到模拟的未来,限制推测!
其他乐观算法
主要目标:避免过度的乐观执行
已提出多种协议,其中包括:
- 基于窗口的方法
- 只在一个移动窗口中执行事件(模拟时间,内存)
- 无风险执行
- 只在消息确保正确时发送
- 向保守协议添加乐观性
- 指定前瞻的“乐观”值
- 引入额外的回滚
- 由随机或内存耗尽触发
- 混合方法
- 混合保守和乐观LPs
- 基于调度的
- 针对回滚过多的LPs进行区分
- 自适应协议
- 根据工作负载变化在执行过程中动态调整协议
乐观算法总结
缺点:
- 内存需求可能很大
- 抖动行为
- 实现通常比保守机制更复杂且难以调试(需要详细分析回滚场景)
- 系统调用,内存分配...
- 必须能够从异常中恢复
- 在联合模拟中使用需要向现有模拟添加回滚能力
优点:
- 在多种应用中报告了良好的性能(排队通信网络,作战模型,运输系统)
- 良好的透明度:为“通用”并行模拟软件提供了最佳希望(比保守方法对差前瞻更具弹性)