9

What exactly is the difference between message passing concurrency schemes and lock-based concurrency schemes, in terms of performance? A thread that is waiting on a lock blocks, so other threads can run. As a result, I don't see how message-passing can be faster than lock-based concurrency.

Edit: Specifically, I'm discussing a message-passing approach like in Erlang, compared to a shared-data approach using locks (or atomic operations).

4

5 回答 5

9

正如其他一些人所建议的那样(“苹果和橙子”),我认为这两种技术是正交的。这里的基本假设似乎是一个将选择一个或另一个:我们将使用锁定和共享资源,或者我们将使用消息传递,并且其中一个使另一个变得不必要,或者另一个甚至不可用。

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

同样地,虽然可以肯定的是,人们可以通过消息传递来实现锁定。一般而言,询问哪个性能更好并没有多大意义,因为这实际上更多的是关于哪个是根据哪个构建的问题。最有可能的是,一个有能力的程序员可以更好地驾驶较低级别的那个,而不是构建在上面的那个——就像直到最近手动变速器汽车的情况一样(那里也有很大的争论)。

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

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

于 2011-08-21T21:19:49.577 回答
6

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

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

  • 在多个线程同时运行的上下文中,可变/共享对象的状态更难推理。
  • 在共享对象上同步会导致算法本质上是非wait free或非的lock free
  • 在多处理器系统中,可以跨处理器缓存复制共享对象。即使使用不需要同步的基于比较和交换的算法,也有可能会花费大量处理器周期向每个处理器发送缓存一致性消息。
  • 由消息传递语义构建的系统本质上更具可扩展性。由于消息传递意味着消息是异步发送的,因此在接收者对消息采取行动之前,发送者不需要阻塞。

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

  • 一些算法往往要简单得多。
  • 需要锁定资源的消息传递系统最终将退化为共享对象系统。当程序员开始使用 ets 表等来存储共享状态时,这在 Erlang 中有时很明显。
  • 如果算法无需等待,您将看到性能提高并减少内存占用,因为新消息形式的对象分配要少得多。
于 2011-08-22T05:08:13.133 回答
2

当您只想锁定错误时使用消息传递。在这些情况下,请使用锁定。然而,消息传递给你的不仅仅是锁定——顾名思义,它允许你在线程或进程之间传递消息,即数据。

于 2011-08-21T19:38:11.237 回答
2

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

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

于 2011-08-21T20:48:55.390 回答
0

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

于 2015-02-15T21:14:20.950 回答