CH08-数据所有权
避免锁带来的同步开销的最简单方式之一,就是在线程之间(或者对于内核来说,CPU 之间)包装数据,以便让数据仅被一个线程访问或修改。这种方式非常重要,事实上,它是一种应用模式,甚至新手凭借本能也会如此使用。
多进程
在前面基于 Shell 的并行编程示例中,两个进程之间不共享内存。这种方法几乎完全消除了同步开销。这种极度简单和最佳性能的组合显然是相当有吸引力的。
部分数据所有权和 pthread 线程库
在第五章“计数”中大量使用了数据所有权技术,但是做了一些改变。不允许线程修改其他线程拥有的数据,但是允许线程读取这些数据。总之,使用共享内存允许更细粒度的所有权和访问权限概念。
纯数据所有权也是常见且有用的。比如前面讨论的每线程内存分配器缓存,在该算法中,每个线程的缓存完全归该线程所有。
函数输送
上面讨论的是一种弱形式的数据所有权,线程需要更改其他线程的数据。这可以被认为是将数据带给他需要的函数。另一种方式是将函数发送给数据。
指派线程
前面的小节描述了允许每个线程保留自己的数据副本或部分数据副本的方式。相比之下,本节将描述一种分解功能的方式,其中特定的指定线程拥有完成其他工作所需的数据的权限。之前讨论的最终一致性计数器实现就提供了一个例子。eventual() 函数中运行了一个指定线程,该线程周期性地将每线程计数拉入全局计数器,最终将全局计数器收敛于实际值。
私有化
对于共享内存的并行程序,一种提升性能的和可扩展性的方式是将共享数据转换成由特定线程拥有的私有数据。
比如使用私有化方式来解决哲学家就餐问题,这种方式具有比标准教科书解法更好的性能和扩展性。原来的问题是 5 个哲学家坐在桌子旁边,每个相邻的哲学家之间有一把叉子,最多允许两个哲学家同时就餐。我们可以通过提供 5 把额外的叉子来简单地私有化这个问题,所有每个哲学家都有自己的私人叉子。这允许所有 5 个哲学家同时就餐,也大大减少了一些传播疾病的机会。
在其他情况下,私有化会带来开销。总之,在并行程序员的工具箱中,私有化是一个强大的工具,但必须小心使用。就像其他同步原语一样,他可能会带来复杂性,同时降低性能和扩展性。
数据所有权的其他用途
当数据可以被分割时,数据所有权最为有效,此时很少或没有需要跨线程访问或更新的地方。幸运的是,这种情况很常见,并且在各种并行编程环境中广泛存在。
- 所有消息传递环境,例如 MPI。
- MapReduce。
- 客户端——服务器系统,包括 RPC、Web 服务好几乎任何带有后端数据库服务的系统。
- 无共享式数据库系统。
- 具有单独的每进程地址空间的 fork-join 系统。
- 基于进程的并行性,比如 Erlang 语言。
- 私有变量,例如 C 语言在线程环境中的堆栈自动变量。
数据所有权可能是最不起眼的同步机制。当使用得当时,它能提供无与伦比的简单性、性能、扩展性。也许他的简单性使他没有得到应有的尊重。
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.