并发数据结构-1.1.4 复杂度测量&1.1.5 正确性

简介:

原文链接译文链接,译者:张军,校对:周可人

1.1.4 复杂度测量

一个被广泛研究的方向是在理想化模型,如并行随机存取机上分析并发数据结构和算法的渐进复杂度[35, 122, 135]。然而,很少有将这些数据结构放在一个真实的多处理器上进行建模的。这里有多种原因,大部分原因跟系统硬件架构与线程异步执行的相互作用有关。想想组合树(combining tree)的例子,虽然我们能通过计算(指令数)得到O(P/logP)的加速比,但这无法反映在实证研究中[52, 129]。真实世界的行为是被上述其他因素支配的,如竞争开销,缓存行为,同步操作(例如CAS)开销,请求到达率,退避延时,数据结构在内存中的布局等等。这些因素很难用一个精确的涵盖目前所有架构的模型来量化。

采集这些方面的复杂度(的)测量方法已经由Dwork [28] ,Anderson,Yang [7]等人提出,虽然这些方法在算法设计上提供了有用的见解,但它们还是不能准确捕捉所有上述因素的影响。因此,并发数据结构的设计者通过在真实机器和模拟架构[9, 52, 97, 103]上运行微基准测试实证地比较他们的设计。在本章的剩余部分,我们普遍地根据这些数据结构基于经验观察到的行为来评价他们,并且用简单的复杂度变量来辅助直觉进行判断。

1.1.5 正确性

很容易发现,简单的基于锁的计数器,其行为跟那些顺序的实现是“相同”的。然而,很明显我们更难看到对合并树(combining tree)而言,同样如此。一般情况下,并发数据结构的实现往往是很精细的,不正确的实现并不少见。因此,声明并严格证明一个特定的设计正确地实现了所要求的并发数据结构是非常重要的。我们不希望达到这些而不精确地指明什么是“正确”。

顺序数据结构的数据结构规格描述通常更容易。例如,我们可以通过选择一组状态,并提供一个以状态,操作名,以及该操作的参数作为函数参数,将新的状态和操作返回值作为函数返回值的转换函数(trainsition function)来指明一个顺序数据结构的语义。加上指定的初始状态,转换函数(transition function)指定了该数据结构上所有可接受操作序列。计数器的顺序语义定义如下:计数器的状态是一组整数,初始状态是0。fetch-and-inc操作的转换函数在旧状态上加一来获取新状态,返回值是计数器的旧状态。

顺序数据结构上的操作是一次一个顺序执行的,我们只简单要求顺序操作的结果遵循如上讨论所指定的顺序语义。然而,对并发数据结构来说,操作不一定完全按照顺序。并发数据结构的正确性条件一般要求有些操作完全按照顺序以满足顺序语义。不同正确性条件的区别在于对总顺序的需求不同。

一个常见的正确性条件是Lamport的顺序一致性(sequential consistency)[81],这要求总顺序上保证每个线程执行操作的顺序。从软件工程的角度来看顺序一致性有个缺点:使用顺序一致性组件实现的数据结构本身可能不是顺序一致的。

一个自然,广泛使用且克服上述问题的正确性条件是Herlihy, Wing的可线性化(linearizability)[58],它是一个用于数据库事务的串行化条件的一个变种。可线性化需要(满足两个特性:(1)该数据结构是顺序一致的 ,(2)使其满足顺序一致性的总体顺序遵循操作执行的实时顺序。遵循实时顺序意味着如果操作O1在操作O2开始之前完成(操作之间不是并发的),那么O1必须排在O2之前。该正确性条件的另外一种理解方式是,它要求我们能够确定每个操作执行时间间隔中的不同点,称为可线性化点,这样,如果我们根据可线性化点的顺序来对操作排序,那么排序结果会遵循顺序一致性语义。

很容易看到,基于锁的计数器是可线性化的,计数器的状态始终存储在变量X中。我们将存储增加后的值到变量X定义为fetch-and-inc操作的可线性化点。基于CAS的无锁(lock-free)实现的计数器的可线性化点同样简单,除了使用CAS指令的语义而不是论证锁语义,我们能得出结论,计数器每被修改一次就加一。

对于合并树(combining tree)来说,很明显我们更难看到它是可线性化的,因为计数器的状态在同一时间不止加一,并且因为一个fetch-and-inc操作实际上可能由之前合并的另一个操作来执行。我们定义基于合并树(combining tree)的计数器上的fetch-and-inc操作的可线性化点如下:当一个获胜线程到达树的根节点并将其累积值加到计数器上时,我们将其之前合并的操作线性化。这些操作根据之后被分发到对应操作的返回值的顺序线性化。虽然详细的可线性化证明超出了我们讨论的范围,但我们应该清楚即使是简单并发数据结构的严格的正确性证明,也是相当具有挑战性的。

直观的吸引力和模块化使可线性化(linearizability)成为一个广受欢迎的正确性条件。在本章剩余部分我们讨论的大部分并发数据结构实现都是可线性化的。然而,在某些情况下,性能和可扩展性可通过满足较弱正确性得到提高。例如,静态一致性(quiescent consistency)条件[10]降低了对总操作顺序满足实时排序的要求,但要求所有静态状态(其中无任何操作执行)之后执行的操作必须排在该状态之前执行的操作之后。一个满足这种弱正确性条件的实现是否有用跟应用有关。相比之下,可线性化的实现始终是有用的,因为设计者可以将其视为具有原子性。

文章转自 并发编程网-ifeve.com

目录
相关文章
|
27天前
|
存储 算法
数据结构与算法:复杂度
数据结构: 数据结构是用于存储和组织数据的方式,以便可以有效地访问和修改数据。不同的数据结构适用于不同类型的应用,并且具体的数据结构可以大幅影响程序的性能。数据结构分为两大类:线性数据结构和非线性数据结构。 算法: 算法是完成特定任务的一系列操作步骤,是解决问题的明确规范。算法的效率通常通过时间复杂度和空间复杂度来评估,即算法执行所需的时间和空间资源。
|
6月前
|
算法 C++
【C++数据结构】算法的复杂度
【C++数据结构】算法的复杂度
|
1月前
|
存储 算法 C语言
【数据结构】复杂度
【数据结构】复杂度
|
1月前
|
存储 算法
【数据结构与算法】3、虚拟头节点、动态数组的缩容、动态数组和单链表的复杂度、数组的随机访问
【数据结构与算法】3、虚拟头节点、动态数组的缩容、动态数组和单链表的复杂度、数组的随机访问
23 0
|
1月前
|
算法
【数据结构】复杂度学习
【数据结构】复杂度学习
|
4月前
|
机器学习/深度学习 存储 算法
【数据结构】复杂度
【数据结构】复杂度
|
4月前
|
机器学习/深度学习 算法 Java
数据结构的复杂度
数据结构的复杂度
19 0
|
4月前
|
搜索推荐 算法 大数据
【数据结构】排序算法复杂度 及 稳定性分析 【图文详解】
【数据结构】排序算法复杂度 及 稳定性分析 【图文详解】
88 1
|
5月前
数据结构-堆排序及其复杂度计算
数据结构-堆排序及其复杂度计算
68 1
|
5月前
|
机器学习/深度学习 存储 算法
【数据结构】第一站:复杂度
【数据结构】第一站:复杂度
42 0

相关实验场景

更多