原文链接,译文链接,译者:周可人,校对:梁海舰

1.1.2 阻塞技术

在很多数据结构中,内存竞争所带来的不良现象和前文所说的顺序瓶颈带来的影响都可以通过使用细粒度锁机制来减小。在细粒度锁机制中,我们用多个粒度较小的锁来保护数据结构中的不同部分。这样做的目的是允许并发操作在它们不访问数据结构的相同部分时并行执行。这种方法也可以用于避免独立内存位置访问的额外竞争。在一些数据结构中,这种现象经常发生;举个例子,在哈希表中,对那些被哈希到不同哈希桶中的值的操作自然访问的是数据结构中的一部分。

对其他的数据结构,如基于锁的共享计数器,怎样减少竞争和降低顺序瓶颈并没有那么清晰,因为抽象地来说,所有的操作都对数据结构的同一部分做修改。一种处理竞争的方法是将所有操作分散在不同时间,从而使每一个操作在不同的时段访问计数器。一种广泛使用的处理技术被称为回退。然而,即使减少了竞争,我们的基于锁的计数器仍然缺少并行性,并且不可扩展。幸运的是,更加细致的技术可以提升可扩展性。

一种技术,被称为“合并树”,可以用来实现一个可扩展的计数器。这种技术使用了一个二叉树,每个叶子表示一个线程。树的根节点存储实际的计数器值,树的其他内部节点用来协调对根节点的访问。其中的核心思想是线程从树的叶子节点向上爬,尝试去和其他并发操作“合并”。每一次两个线程的操作在一个内部节点合并,其中一个线程(失败者),简单地在当前节点等待,直到一个返回值传递给它。另外一个线程(胜利者),朝着根节点向上,携带所有在该节点子树中合并的操作之和;一个到达根节点的胜利者线程将它的和增加到计数器中,因此所有合并的操作增长被加到计数器中。之后这个胜利者在树中下降,分发一个返回值给每一个之前合并的,处在等待状态的失败者线程。这些返回值被分发下来,这样的效果就好像所有增长操作都在根计数器被修改的时刻一个接着一个的执行。

在合并树中,失败者在等待胜利者时所使用的技术对性能而言是重要的。一个失败者采用重复地读取一个树节点的一个内存地址的方式操作等待,这被称为自旋。在缓存一致性多核处理器中,一个重要的推论是这个位置会位于运行失败者操作的处理器的本地缓存,直到胜利者操作报告结果。这意味着等待的失败者并没有产生任何不必要的,并且可能降低胜利者性能的内存流量。这种等待被称为本地自旋,且已经被证实对提升可扩展性来说至关重要。

在所谓的非一致性内存访问(NUMA)架构中,处理器访问他们的共享存储中本地存储部分要比访问其他处理器的部分要快的多。在这样的架构中,数据布局——合并树中节点在内存中的分布方式——对性能有着显著的影响。将树的叶子节点存放在处理相应线程的处理器附近可以提升性能。(我们假设线程是和处理器静态绑定的)

数据布局的问题也对缓存一致性多核处理器上并发数据结构的设计有影响。回顾合并树的一个作用是减少独立内存位置的竞争,从而提升性能。然而,因为缓存一致性多核处理器用缓存行大小的块管理内存,如果两个线程访问不同内存区域,落在了相同的缓存行中,会和他们访问同一块内存地址一样受到性能影响。这种现象被称为伪共享,这是一个常见的,令人困惑的性能问题。

在减少独立内存位置的竞争,用本地自旋减少内存流量,允许操作并行执行之后,用合并树实现的,随着并发线程的数量扩展的计数器,比单锁版本的计数器要好的多。如果所有线程被用于不断合并,那么一个P宽度的树允许P个线程在O(logP)个(合并树中的)上升和下降的操作之后,返回P个值,提供了O(P/logP)的加速比。

尽管使用合并树的方式有很多优点,但是它也有一些不足之处。合并树需要限定P个线程访问计数器,并且需要O(P)的空间。虽然它在高负载下能提供更高的吞吐量,即在树被大量线程访问时,但它在低负载访问时的最好性能是差的:它必须遍历树中的O(logP)个节点,然而一个基于单锁的fetch-and-inc操作在常数时间内可以完成。此外,如果一个线程因为它在一个胜利者线程离开树向上后马上到达导致合并失败,那么它必须等待,直到胜利者返回才能继续向上。如果上升的胜利者,失败者,以及之后的上升线程之间的协调处理错误,那么可能会导致死锁:线程可能以循环的方式互相阻塞,没有一个可以继续执行。避免死锁显著地增加了设计正确,并且高效的阻塞并发数据结构的复杂性。

总的来说,如果在使用足够的阻塞来达到正确,和尽量降低阻塞来允许并发操作并行执行之间达到平衡,阻塞数据结构可以提供强大的,高效的实现。

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

并发数据结构-1.1.2 阻塞技术相关推荐

  1. qt 5编程入门(第2版)_《C++并发编程实战第2版》第六章:设计基于锁的并发数据结构(1/3)...

    本章主要内容 设计并发数据结构的含义 设计指南 并发数据结构的示例实现 在上一章中我们了解了底层原子操作和内存模型.本章我们先把底层的细节放一放(尽管在第7章我们将需要它们),探讨一下数据结构. 为编 ...

  2. 并发数据结构- 1.1.1 性能

    原文链接,译文链接,译者:俞升兵,校对:周可人 1.1.1 性能 一个运行在P个处理上的应用程序的加速度是它在单个处理器上的执行时间和在P个处理器的执行时间的比值.这是一种评价应用程序对于机器资源利用 ...

  3. 并发编程 — 并发数据结构--转载

    并发编程系列文章:        初解线程池:http://ray-yui.iteye.com/blog/2072463        详解线程池:http://ray-yui.iteye.com/b ...

  4. 处理大并发之一 对异步非阻塞的理解

    处理大并发之一 对异步非阻塞的理解 在研究nginx和node.js的时候常会遇到异步.非阻塞等,之前自己也经常使用epoll,对其同步与阻塞,异步与非阻塞有了一定的认识,现对参考资料总结下. 首先讨 ...

  5. 并发数据结构 : SpinWait

    老实说,没有哪个开发人员愿意在其编码时还要考虑线程同步.更糟糕的情况是,编写线程同步代码一点也不好玩.稍一不慎,就会导致共享资源状态不一致,从而引发程序未预期行为.此外,当我们添加线程同步代码时还会导 ...

  6. 并发数据结构-1.1 并发的数据结构的设计

    原文链接,译文链接,译者:董明鑫,校对:周可人 随着多个处理器共享同一内存的机器在商业上的广泛使用,并发编程的艺术也产生了巨大的变化.当前的趋势向着低功耗芯片级多线程(CMT)发展,所以这样的机器一定 ...

  7. Java 并发数据结构

    java 并发数据结构 并发数据结构在数据添加和删除时: 阻塞式集合:当集合为空或满时:等待: 非阻塞式集合:当集合为空或在满时:不等待,返回null或异常. 1. List 不安全: ArrayLi ...

  8. 并发编程5:Java 阻塞队列源码分析(下)

    上一篇 并发编程4:Java 阻塞队列源码分析(上) 我们了解了 ArrayBlockingQueue, LinkedBlockingQueue 和 PriorityBlockingQueue,这篇文 ...

  9. 打通 Java 任督二脉 —— 并发数据结构的基石

    老大难的 Java ClassLoader,到了该彻底理解它的时候了 每一个 Java 的高级程序员在体验过多线程程序开发之后,都需要问自己一个问题,Java 内置的锁是如何实现的?最常用的最简单的锁 ...

最新文章

  1. 领域驱动设计_软件核心复杂性应对之道
  2. Bio+IT 爱好者社区,欢迎你!
  3. python3 multiprocessing 多进程 列表类型 listproxy 清除内容
  4. python中哪个函数是用于输出内容到终端的_尔雅通识课妇产科护理学(山东联盟-潍坊医学院)答案新版...
  5. mysql卸载后root还在_CentoOs7 Mysql卸载后重新安装缺少/root/.mysql_secret
  6. textedit实时显示位置_加什么地形就看什么等高线!等高线实时预览就是这么爽...
  7. MAC VSCode Go代码第一次运行配置
  8. java系统性能优化之mysql数据库优化
  9. 怎么将webm格式转换为mp4
  10. 海康威视球形摄像头激活,web二次开发
  11. Air202学习(4)官方例程(luat版)
  12. 阿里双十一购物节背后的技术问题
  13. 双非计算机研究生要不要读,“双非”大学研究生,到底值不值得读?
  14. 计算机关机键桌面,电脑关机快捷键是什么?
  15. 移动Web:媒体查询及手机端PC端识别
  16. 安装win10时无法安装若要在此计算机,win10安装时遇问题如何解决 win10安装解决方案...
  17. 五年程序员谈软件工程师做职业规划的重要性
  18. 使用功耗分析仪,对一款LORA低功耗温度传感器进行功耗评测,评估温度传感器的待机时长,供参考。
  19. Spring Cloud 学习笔记(1 / 3)
  20. http的常见错误代码

热门文章

  1. Windows实用快捷键
  2. 交互式计算机图形学总结:第七章 离散技术
  3. flutter-Text 以字符的方式截断
  4. 连接数据库版本不一致
  5. java之整数的分解可以理解为倒序输出
  6. 10、mybatis参数处理
  7. java map赋值给model_Map,Model,ModelMap使用方法
  8. 【参会指南】神策 2020 数据驱动用户大会,10 月 13 日将重磅开幕!
  9. 愿只有一个Grid Layout
  10. TensorFlow模型保存和加载方法