并发数据结构-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]降低了对总操作顺序满足实时排序的要求,但要求所有静态状态(其中无任何操作执行)之后执行的操作必须排在该状态之前执行的操作之后。一个满足这种弱正确性条件的实现是否有用跟应用有关。相比之下,可线性化的实现始终是有用的,因为设计者可以将其视为具有原子性。 

目录
相关文章
|
1月前
|
存储 缓存 持续交付
后端世界的微妙平衡:性能与可维护性的博弈###
【10月更文挑战第15天】 在软件开发的浩瀚宇宙里,后端开发犹如一颗星辰,既需璀璨夺目以支撑业务辉煌,又得稳若磐石确保系统长青。本文探讨了后端开发中性能优化与代码可维护性之间的微妙平衡,通过实例分析与策略建议,揭示了如何在追求极致速度的同时,保持代码的清晰、可读与易于迭代,实现技术与艺术的和谐共生。我们相信,正如印度圣雄甘地所言:“你必须成为你希望在世界上看到的改变。”开发者在面对复杂系统挑战时,也应主动寻求变革,探索更高效的解决方案。 ###
37 3
|
1月前
|
测试技术
软件复杂度量化:McCabe度量法及其环路复杂度的计算方法
McCabe度量法(McCabe's Cyclomatic Complexity)是一种经典的方法,用于度量软件程序的复杂度。通过计算程序中独立路径的数量,帮助开发人员评估代码的维护难度和测试覆盖率。本文详细介绍了McCabe度量法的原理、计算方法及其在实际应用中的作用。
294 0
WK
|
2月前
|
算法 决策智能
粒子群算法的缺点是什么
粒子群算法(PSO)虽具优点,但存在明显缺点:易陷局部最优、收敛精度低、难解离散及组合优化问题、缺乏精密搜索方法、理论基础薄弱、参数选择困难、收敛速度受问题复杂度影响。为克服这些问题,研究者提出引入动态惯性权重、调整学习因子、混合算法等改进策略,提高算法性能与适用范围,但仍需进一步研究以应对更复杂多样的问题。
WK
102 0
|
3月前
|
微服务
软件设计与架构复杂度问题之理解软件复杂性的递增性如何解决
软件设计与架构复杂度问题之理解软件复杂性的递增性如何解决
|
3月前
|
设计模式
软件设计与架构复杂度问题之认知负荷的定义如何解决
软件设计与架构复杂度问题之认知负荷的定义如何解决
|
4月前
软件复用问题之减少软件系统中的“熵增”,如何解决
软件复用问题之减少软件系统中的“熵增”,如何解决
|
4月前
软件复用问题之如果无法进行定量分析,评估系统的复用性要如何解决
软件复用问题之如果无法进行定量分析,评估系统的复用性要如何解决
|
4月前
软件复用问题之度量组件的可靠性,如何解决
软件复用问题之度量组件的可靠性,如何解决
|
5月前
|
Java 数据库 图形学
论系统的木桶理论与性能瓶颈
论系统的木桶理论与性能瓶颈
61 7
|
6月前
|
存储 负载均衡 并行计算
实现优雅并行编程:确保正确性与提升性能的关键要素
在程序开发中,并行编程一种利用多个处理器或计算资源同时执行多个任务的编程方式,它能够提高计算效率和性能,是提高计算效率和性能的关键手段,但它也带来了一系列复杂的问题,涉及到任务分解、数据同步、资源分配等诸多复杂问题,稍有不慎就可能导致性能瓶颈、死锁甚至数据不一致等状况。编写优雅的并行程序需要在保证程序正确性的前提下,实现高效的并行计算。那么本文就来探讨一下如何在保证程序正确性的前提下,实现优雅的并行程序,以提升计算效率和性能,包括任务分解、数据同步和资源分配等方面的关键要素,希望能够为读者提供一些有用的指导和启示。
120 2
实现优雅并行编程:确保正确性与提升性能的关键要素
下一篇
无影云桌面