并发译文 ’ 目录归档

深入理解并行编程-分割和同步设计(三)

原文链接    作者:paul    译者:谢宝友,鲁阳,陈渝

设计准则

上面的章节中给出了三个并行编程的目标:性能、生产率和通用性。但是还需要更详细的设计准则来真正的指导真实世界中的设计,这就是本节将解决的任务。在真实世界中,这些准则经常在某种程度上冲突,这需要设计者小心的权衡得失。

这些准则可以被认为是设计中的阻力,对这些阻力进行恰当权衡,这就称为“设计模式”[Ale79],[GHJV95]。

基于三个并行编程目标的设计准则是加速、竞争、开销、读写比率和复杂性。 阅读全文

硬件的习性

原文链接    作者:paul    译者:谢宝友,鲁阳,陈渝

大多数人根据直觉就知道,在系统间传递消息要比在单个系统上执行简单计算更加耗时。不过,在共享同一块内存的系统的线程间传递消息是不是也更加耗时,这点可就不一定了。本章主要关注共享内存系统中的同步和通信的开销,只涉及了一些共享内存并行硬件设计的皮毛,想了解更多信息的读者,可以翻看Hennessy和Patterson的经典教材最新版[HP95]。

小问题4.1:为什么并行软件程序员需要如此痛苦地学习硬件的低级属性?如果只学习更高级些的抽象是不是更简单,更好,更通用?

阅读全文

软件事务内存导论

  1. 前言
  2. 软件事务内存
  3. 用Akka/Multiverse STM实现并发
  4. 创建事务
  5. 创建嵌套事务
  6. 配置Akka事务
  7. 阻塞事务
  8. 提交和回滚事件
  9. 集合与事务
  10. 处理写偏斜异常
  11. STM的局限性

软件事务内存导论(十一)-STM的局限性

声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。

1.1    STM的局限性

STM消除了显式的同步操作,所以我们在写代码时就无需担心自己是否忘了进行同步或是否在错误的层级上进行了同步。然而STM本身也存在一些问题,比如在跨越内存栅栏失败或遭遇竞争条件时我们捕获不到任何有用的信息。我似乎可以听到你内心深处那个精明的程序员在抱怨“怎么会这样啊?”。确实,STM是有其局限性的,否则本书写到这里就应该结束了。STM只适用于写冲突非常少的应用场景,如果你的应用程序存在很多写操作竞争,那么我们就需要在STM之外寻找解决方案了。

下面让我们进一步讨论STM的局限性。STM提供了一种显式的锁无关编程模型,这种模型允许多个事务并发地运行,并且在没有发生冲突时所有事务都能毫无滞碍地运行,所以相对其他编程模型而言STM可以提供更好的并发性和线程安全方面的保障。当事务对相同对象或数据的写访问发生冲突时,只有一个事务能够顺利完成,其他事务都会被自动重做。这种重做机制延缓了写操作冲突时竞争失败的那些写者的执行,但却提升了读者和竞争操作的胜利者的执行速度。当对于相同对象的并发写操作不频繁时,其性能就不会受到太大影响。但是随着冲突的增多,程序整体性能将因此变得越来越差。
阅读全文

Mutex和内存可见性

原文链接  作者:Loïc  译者:林永听

介绍

POSIX线程遵守共享内存模型[1],此模型各线程可以访问一组共享对象。多个并发的线程需要协同访问共享对象。为此该模型引入了以下两个属性来简化程序设计:

  • 原子访问:避免线程在访问数据对象时,另一线程正在修改它。
  • 内存可见性:一旦线程修改数据对象,其它线程在修改行为发生之后马上能看见此对象的新状态,如图1所示。

阅读全文

软件事务内存导论(十)处理写偏斜异常

声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。

处理写偏斜异常

在6.6节中,我们曾经简单讨论了写偏斜(write skew)以及Clojure STM是如何解决这个问题的。Akka同样提供了处理写偏斜问题的支持,但是需要我们配置一下才能生效。OK,一听到配置这个词可能让你觉得有些提心吊胆,但实际操作起来其实起来还是蛮简单的。下面就让我们首先了解一下Akka在不进行任何配置情况下的默认行为。

阅读全文

软件事务内存导论(九) 集合与事务

声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。

集合与事务

在我们努力学习这些示例的过程中,很容易就会忘记我们所要处理的值都必须是不可变的。只有实体才是可变的,而状态值则是不可变的。虽然STM已经为我们减轻了很多负担,但如果想要在维护不可变性的同时还要兼顾性能的话,对我们来说也将是一个非常严峻的挑战。

为了保证不可变性,我们采取的第一个步骤是将单纯用来保存数据的类(value classes)及其内部所有成员字段都置为final(在Scala中是val)。然后,我们需要传递地保证我们自己定义的类里面的字段所使用的类也都是不可变的。可以说,将字段和类的定义置为final这一步是整个过程的基础,这同时也是避免并发问题的第一步。

虽说不可变性可以使代码变得又好又安全,但是由于性能问题,程序员们还是不大愿意使用这一特性。其症结在于,为了维护不可变性,我们可能在数据没发生任何变动的情况下也要进行拷贝操作,而这种无谓的拷贝对性能伤害很大。为了解决这个问题,我们在3.6节中曾经讨论过持久化数据结构以及如何使用这类数据结构来减轻程序在性能方面的负担。而在持久化数据结构的实现方面,已经有很多现成的第三方库可供使用,而Scala本身也提供了这类数据结构。由于Java也有实现好的持久化数据结构可用,所以我们就无需专门为使用这个特性而去换用自己不熟悉的语言。

除了不可变性之外,我们还希望能获得一些事务运行所需要的数据结构——这些数据结构的值是不可变的,但其实体可以在托管事务中被改变。Akka提供了两种托管数据结构——TransactionalVector和TransactionalMap。这两种数据结构源自于高效的Scala数据结构,其工作原理和Java的list、map类似。下面就让我们一起来学习如何在Java和Scala中使用TransactionalMap

阅读全文

Java 7 Concurrency Cookbook – Javier Fernández González -前言

原文下载链接      作者: Javier Fernández González     译者:郑玉婷

前言

当你用计算机工作的时候,你在同时做多样事情。你可以边听音乐边写文档边读取邮件。你可以这样做的原因是你的操作系统运行并发任务。并发编程是关于基础与进程的一个 提供多任务或者程序同时运行还相互沟通来交换数据和相互同步的平台。Java是一个并发平台,在Java程序中提供很多执行并发任务的类。每个版本,Java提升了促进程序员开发并发程序的功能。这本书包含了在Java版本7的并发API中最重要和最有用的技巧,所以你可以直接在你的应用程序中使用的,以下这些:

• 基本线程管理
• 线程同步机制
• 执行者代表的线程的创建与管理
• Fork/Join框架来提高应用程序的性能
• 并发程序的数据结构
• 按照需要来调整一些并发类的默认行为
• 测试Java的并发应用程序

阅读全文

深入理解并行编程-分割和同步设计(二)

原文链接    作者:paul    译者:谢宝友,鲁阳,陈渝

双端队列是一种元素可以从两端插入或删除的数据结构[Knu73]。据说实现一种基于锁的允许在双端队列的两端进行并发操作的方法非常困难[Gro07]。本节将展示一种分割设计策略,能实现合理且简单的解决方案,请看下面的小节中的三种通用方法。

阅读全文

C1X 系列 : 多线程 (N1494)

感谢林永听投递本文。  校对:方腾飞

1. 关于 C1X 标准

C1X 是 C 语言的下一个标准,用于取代现有的 C99 标准。 C1X 是一个非正式名字,该标准仍在制订中,最新的工作草案是 N1494 ,发布于 2010 年 6 月。与 C99 相比, C1X 在语言和库上有显著的变化,本文重点分析 N1494 草案中的多线程部分。

2. 呼之欲出的多线程

不瞒你说, C99 标准里面的内存模型仍然是单线程的,即所有代码都运行在一个线程(进程)内。也许,你简直不敢相信这个是真的,因为说不定你每天都与多线程打交道, 使用 _beginthread , CreateThread 或 pthread_create 等不同平台的函数去创建线程。当你担心每个变量被编译器优化时,不得不加上 volatile 修饰符时,或者加上内存栅栏 (memory barrier) ,都印证了 C99 为单线程的内存模型。

32 位保护模式的出现,催生了多任务操作系统的诞生,随之而来的就是多线程环境。随着多核时代的到来,多线程环境成为程序开发不可逃避的问题。无锁编程,并行编程等已经成熟的技术在 C 社区里,常常给初学者遥不可及的感觉。在迫切需要多线程的时代,不同厂商和平台都纷纷开发了各自的多线程库,如 POSIX 的 pthreads 和 window 的 winThread 。软件工程师在特定的平台下,使用各自的线程库来开发多线程或并发程序,并非很难,但可移植却成了他们面临的问题。如 pthreads 在默认情况下,互斥锁是非递归的,要使用递归互斥锁,程序库必须支持一些扩展 feature ;而 window 下的锁默认情况下是递归的。 lock-wait-wakup 方式也不尽然相同,这对开发跨平台的多线程程序来说无异于雪上加霜。

放眼 C 语言的后来者,如 Java ,很早就支持了多线程,并且它的内存模型在不断地修改,以适应发挥多线程的优势。 Erlang 作为一种天生的并发编程语言,踏上编程语言的行列,成为并发编程的新星。同时,很多脚本语都内置地支持线程类或结构。 C/C++ 作为后来加入到多线程的行列,尽管已经太晚了,但对于 C 语言社区来说,这无疑是最令人兴奋的消息了。

阅读全文

软件事务内存导论(五)创建嵌套事务

声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。

1.1    创建嵌套事务

在之前的示例中,每个用到事务的方法都是各自在其内部单独创建事务,并且事务所涉及的变动也都是各自独立提交的。但如果我们想要将多个方法里的事务调整成一个统一的原子操作的时候,上述做法就无能为力了,所以我们需要使用嵌套事务来实现这一目标。

通过使用嵌套事务,所有被主控函数调用的那些函数所创建的事务都会默认被整合到主控函数的事务中。除此之外,Akka/Multiverse还提供了很多其他配置选项,如新隔离事务(new isolated transactions)等。总之,使用了嵌套事务之后,只有位于最外层的主控函数事务提交时,其内部所做的变更才会被提交。在具体使用时,为了保证所有嵌套事务能够作为一个整体成功完成,我们需要保证所有函数都必须在一个可配置的超时范围内做完。
阅读全文

为代码签名,供后人瞻仰或唾弃,你敢吗?

如何衡量代码质量的好坏,是否有一个标准,是否可以量化?

我认为答案是否定的。如果今年中央给各省下个死命令,要求年度GDP增长达到10%,我相信每个省一定都能完成任务。这几年,GDP增长都在8%以上,CPI增长不到4%,民族复兴完成了62%,这些都量化的,你是否满意?

回到开发的问题上来,有一些数字,比如bug的个数,reopen的次数能说明一定的问题,但不是全部。它只能描述系统的外在质量的一部分,这个外在质量可以由QA来保证。但是内部质量只能靠开发自己来保证,牺牲内部质量来保证功能和外在质量是不应该的。 阅读全文

深入理解并行编程-分割和同步设计(一)

原文链接     作者:paul    译者:谢宝友,鲁阳,陈渝

在商用计算机中,多核系统已经越来越常见了,本章将描述如何设计能更好利用多核优势的软件。我们将介绍一些习语,或者叫“设计模式”,来帮助您权衡性能、可扩展性和响应时间。在上一章我们说过,您在编写并行软件时最重要的考虑是如何进行分割。正确的分割问题能够让解决办法简单、可扩展并且高性能,而不恰当的分割问题则会产生缓慢且复杂的解决方案。
阅读全文

Linux内核的内存屏障

原文链接 作者:David HowellsPaul E. McKenney 译者:曹姚君 校对:丁一

内容:

  1. 抽象的内存访问模型
  2. 什么是内存屏障?
  3. 显式内核屏障
  4. 隐式内核内存屏障
  5. CPU之间的锁屏障效应
  6. 什么地方需要内存障碍?
  7. 内核的I/O屏障效应
  8. 假想的最小执行顺序模型
  9. CPU缓存的影响
  10. CPU能做到的
  11. 使用示例
  12. 引用

阅读全文

无锁并发和无等待并发的对比分析

原文地址:作者:rethinkdb  译者:sooerr 校对:方腾飞

有两种非阻塞线程同步算法,即无锁和无等待,这两种算法经常会产生混淆。

在无锁系统中,当任何特定的运算被阻塞的时候,所有CPU可以继续处理其他的运算。换种方式说,在无锁系统中,当给定线程被其他线程阻塞的时候,所有CPU可以不停的继续处理其他工作。无锁算法大大增加系统整体的吞吐量,因为它只偶尔会增加一定的交易延迟。大部分高端数据库系统是基于无锁算法而构造的,以满足不同级别。

相反,无等待算法保证了所有CPU在连续处理有效工作的时候,没有运算会被其他运算所阻塞。相比于无锁算法,无等待算法有更强的保证,并且不会以交易延迟为代价,来保证高吞吐量。当然,相比之下这种算法也更难实现,测试和debug。Linux kernel的无锁页面缓存就是无等待系统的一个典型案例。 阅读全文

return top