消息传递与锁定

时间:2011-08-21 19:27:38

标签: concurrency message-passing

在性能方面,消息传递并发方案和基于锁的并发方案之间究竟有什么区别?正在等待锁定的线程阻塞,因此其他线程可以运行。因此,我没有看到消息传递如何比基于锁的并发更快。

编辑:具体来说,我正在讨论像Erlang中的消息传递方法,与使用锁(或原子操作)的共享数据方法相比。

5 个答案:

答案 0 :(得分:9)

正如其他人所说(“苹果和橘子”),我认为这两种技术是正交的。这里的基本假设似乎是一个人会选择一个或另一个:我们要么使用锁定和共享资源我们将使用消息传递,而另一个则使另一个不必要,或者可能另一个甚至无法使用。

就像一个元叶评估者一样,这里的真实原语并不明显。例如,为了实现消息传递,您可能需要原子 CAS 和特定的内存可见性语义,或者某些锁定和共享状态。可以根据锁实现原子操作,也可以根据原子操作实现锁(就像Java在java.util.concurrent.locks类型中所做的那样)。

同样,虽然不可否认是一个延伸,但可以通过消息传递实现锁定。询问哪一个表现更好一般来说没有多大意义,因为这实际上是一个关于哪个是建立在哪个方面的问题。最有可能的是,位于较低级别的那个可由一个有能力的程序员驱动,而不是建立在顶级的程序员 - 直到最近一直是手动变速器汽车的情况(在那里也是一个很大的争论)

通常,消息传递方法不是为了获得更好的性能,而是为了安全和方便,并且通常通过拒绝程序员对锁定和共享资源的控制来销售。结果,它打击了程序员的能力;如果程序员无法获得锁定,他就无法做得很差并且减慢了程序的速度。就像关于手动内存管理和垃圾收集的争论一样,有些人会声称自己是“好的驱动因素”,充分利用手动控制;其他人 - 特别是那些实施和推广使用垃圾收集器的人 - 将声称,总的来说,收集者可以做得比“不太好的司机”更好,可以通过人工管理。

没有绝对的答案。这里的差异在于程序员的技能水平,而不是他们可能使用的工具。

答案 1 :(得分:4)

恕我直言,消息传递可能不是一个并发方案。它基本上是(IPC)进程间通信的一种形式,是共享对象的替代方案。 Erlang只是赞成将消息传递给共享对象。

共享对象的缺点(Pros od Message Passing):

  • 在多个线程并发运行的上下文中,Mutable / Shared对象的状态更难以推理。
  • 在共享对象上进行同步会导致算法本身不是wait free或非lock free
  • 在多处理器系统中,可以跨处理器缓存复制共享对象。即使使用不需要同步的基于比较和交换的算法,也可能需要花费大量处理器周期来向每个处理器发送缓存一致性消息。
  • 由Message传递语义构建的系统本质上更具可伸缩性。由于消息传递意味着消息是异步发送的,因此发送方不需要阻塞,直到接收方对消息进行操作。

共享对象的优点(消息传递的缺点):

  • 有些算法往往更简单。
  • 需要锁定资源的消息传递系统最终会退化为共享对象系统。当程序员开始使用ets表等来存储共享状态时,这在Erlang中有时很明显。
  • 如果算法是等待的,您将看到改进的性能和减少的内存占用,因为新消息形式的对象分配更少。

答案 2 :(得分:2)

当你想要做的就是锁定时使用消息传递是错误的。在这些情况下,使用锁定。但是,消息传递为您提供的不仅仅是锁定 - 顾名思义,它允许您在线程或进程之间传递消息,即数据。

答案 3 :(得分:2)

消息传递(使用不可变消息)更容易正确。使用锁定和共享可变状态,很难避免并发错误。

至于性能,最好自己测量一下。每个系统都不同 - 工作负载特征是什么,操作是依赖于其他操作的结果还是完全或大部分独立(这将允许大规模并行),延迟或吞吐量更重要,有多少台机器等。锁定可能会更快,或者再次传递消息,或者完全不同的东西。如果与LMAX中相同的方法适合手头的问题,那么可能就是这样。 (我会将LMAX架构归类为消息传递,尽管它与基于actor的消息传递非常不同。)

答案 4 :(得分:0)

消息传递不使用共享内存,这意味着它不需要锁,导致每个线程(进程)只能加载或存储自己的内存,它们相互通信的方式是发送和接收消息。