【问题标题】:Thread-ring benchmark螺纹环基准
【发布时间】:2011-04-01 17:11:44
【问题描述】:

今天我正在做 Programming Erlang 一书中的线程环练习,并在 Google 上搜索其他解决方案以进行比较。我发现语言枪战与benchmark 有完全相同的问题。我的印象是,这是 Erlang 应该很快的领域,但事实证明 C 和 C++ 再次名列前茅。我的怀疑是 C/C++ 程序没有遵循“将令牌从线程传递到线程”的规则。在阅读它们之后,它们似乎都在操纵一些与 Erlang 代码不同的共享内存和全局变量,但我可能是错的。

我的问题是:他们是在做同样的事情,还是 C/C++ 代码在概念上与 Erlang 代码不同(而且更快)?

还有一个问题:为什么在解决方案非常相似的情况下 Haskell 比 Erlang 快?

【问题讨论】:

  • 其中一些比较是苹果和橙子的比较。这样做的原因是,如果您只想让事情快速循环,那么您当然可以在 C 和 C++ 中更快地做到这一点。恕我直言,Erlang 处理的不仅仅是“在进程之间发送令牌”(它是进程而不是线程;))。不久前我写了一篇关于其中一些差异的文章;值得一试:forum.trapexit.org/viewtopic.php?t=15194trapexit.org/Process_Ring_Across_Nodes
  • 这是一个很好的例子,你给出的定义是我对所有解决方案的期望。有没有人尝试用另一种语言重写它,有什么结果吗?另外,你能想到一些 Erlang 在速度方面表现出色的单节点基准测试吗?
  • Joe Armstrong 的观点很简单,“Erlang 中休眠进程之间的消息传递速度非常快……Java 大约慢 5 到 10 倍。” (Java 程序员已经减少了这种差异。)[Java 线程和 Erlang 进程的性能测量 1998-11-02]

标签: c++ c haskell concurrency erlang


【解决方案1】:

C 版本使用的是 LWP,我认为它是一个用户空间线程库。这在多大程度上是“不公平的”是有争议的:我会看看它是否支持真正的抢先并发,因为你可以在一个线程中进行阻塞系统调用而不阻塞所有其他线程(你可以在 Haskell 中执行此操作,在 Erlang 中可以吗?)。

Haskell 的线程比 Erlang 的稍微轻一些,因为据我了解,Erlang 线程带有一个本地堆(在标准实现中),而 Haskell 线程都共享同一个堆。

【讨论】:

【解决方案2】:

最终,现代机器上的消息传递是使用某种形式的共享内存来实现的(连同锁或原子指令)。因此,所有 C 和 C++ 实现实际上都在将消息传递的实现直接内联到它们的代码中。可以在本文中找到使用 C 语言中的快速消息传递库的类似基准测试,也针对 Haskell 和 Erlang 进行基准测试:http://www.cs.kent.ac.uk/pubs/2009/2928/index.html(第 5.1 节)

各种方法的速度实际上是由所涉及的并发运行时系统决定的。 Haskell 在这方面做了很多出色的工作,领先于 Erlang。当然,在微基准上测量速度通常会产生误导,并且会遗漏代码的可读性等重要因素。需要牢记的一个问题可能是:在点球大战中,您愿意维持哪些解决方案?

【讨论】:

  • 取决于哪个赚更多钱:)
  • >> 当然,在微基准上测量速度通常会产生误导,并且会遗漏代码的可读性等重要因素。
【解决方案3】:

我不认为我会称之为作弊。多线程和多进程之间的主要基本区别是多个线程共享一个地址空间。因此,在我看来,指定多个线程(而不是多个进程)似乎是利用共享地址空间的默认许可(至少在没有一些非常具体的“通过”定义禁止这样做的情况下)。

归根结底是:Erlang 并没有真正的线程——它有异步通信的进程。这些过程(有意地)在很大程度上彼此隔离。一方面,这使得开发变得相当容易——特别是,一个过程只能通过特定的、明确定义的通信渠道影响另一个过程。在幕后,它使用了许多技巧(几乎可以肯定包括共享内存)来优化其进程并利用特定实现/情况下的可能性(例如在单个共享地址空间中运行的所有进程)。尽管如此,必须隐藏所有技巧使其无法像 C 版本那样高效,其中“技巧”全部明确且完全公开。

我会使用现实生活中的类比来解释差异。将线程/进程视为人。 Erlang 强制执行专业的工作关系,其中所有通信都仔细记录在备忘录中。 C 和 C++ 版本更像是一对夫妻,他们可能会用一个对其他人没有任何意义的词进行交流,甚至只是简单的一瞥。

后者在起作用时非常有效——但它更容易产生微妙的误解,如果两者发生争执,你可能不想在同一个房间里。对于经理来说,纯粹的职业关系中的人更容易管理,即使他们的最高效率不是很高。

【讨论】:

    【解决方案4】:

    当解决方案非常相似时,为什么 Haskell 比 Erlang 快?

    Haskell GHC 是一种经过编译、本机代码优化的语言实现,具有非常快的线程。它通常比 Erlang/HIPE 快得多。 Erlang 没有垄断轻量级线程 :-)

    【讨论】:

      【解决方案5】:

      我会用另一个问题来回答:Erlang 运行时是如何在后台实现的?

      它可能是用 C 或类似的系统语言实现的(我怀疑他们都是用汇编语言完成的)。或者至少,它们表达的概念可以用 C 有效地表达。

      现在,考虑到 Erlang 增加了自己的复杂性/间接级别,为什么您会觉得优化的 C 版本(枪战肯定不会显示平均级别的代码)会击败 Erlang 版本如此奇怪?

      无论哪种类型的基准测试,C 实现总是有可能击败另一种语言中最精致的程序...建立在 C 之上,仅仅因为您采用它生成的 C 版本,然后删除您创建的位不需要。

      另一方面:

      • 您花了多少时间编写代码?
      • 您对它做正确事情的信任程度如何?不会死锁吗?
      • 您更愿意维护哪一个?

      有时“更快”是不值得的。

      【讨论】:

      • 是的,这是我的问题,如果不同的解决方案处于同一抽象级别。我想我们都同意他们不在这种情况下。至于你的问题——绝对不是 C/C++ 程序。
      【解决方案6】:

      不遵守规则

      考虑到编程并发性有很多非常不同的方法,我确实发现很难既具有足够的包容性以引入不同的语言实现,又要保留一些模糊的可比性。

      现在看看用different run time configuration 测量的相同程序的性能,并注意它的重要性 -

      SMP quad core 
      1.0 C GNU gcc #3    4.16    4.17    16,952  607   100% 0% 1% 0%
      4.2 Haskell GHC     17.99   17.42   4,020   307   100% 1% 1% 1%
      7.5 Erlang HiPE     31.12   31.13   10,504  273   0% 0% 0% 100%
      
      No SMP one core
      1.0 C GNU gcc #3    4.16    4.16    16,952  607   1% 0% 0% 100%
      1.4 Haskell GHC     5.89    5.89    3,204   307   0% 0% 0% 100%
      2.6 Erlang HiPE     10.64   10.63   9,276   273   0% 0% 0% 100%
      

      【讨论】:

      • 要求使用完全抢占式线程抽象怎么样? (没有线程可以阻止任何其他线程取得进展)
      • 不考虑这是否是一件“好事”,前 10 个程序中的哪一个会被排除在外?
      • 关于 GHC 较慢的 4 核结果,我们是否允许使用处理器亲和性来改善它?
      • 我不知道有多少程序(如果有的话)会被要求抢占式线程排除在外。不过,这似乎是一个明智的要求——如果基准测试能够衡量对大多数用户有用的抽象的性能,那么它就具有最大的价值。非抢占式线程有其用处,但我认为大多数用户都需要抢占式。
      • GHC 线程在分配之前仍然不会抢占,是吗?
      【解决方案7】:

      在该基准测试中需要注意的一点是,只有一个令牌可以传递。这意味着在实践中它只是一个从/向内存读取和写入的单线程程序。

      我希望在线程/进程必须以某种随机顺序传递 M 个令牌的多处理器机器(或使其成为集群)上,结果会有所不同。

      嗯。还要给基准解决方案的开发人员相同的小时数来完成他们的解决方案。那么我希望 Erlang 能够脱颖而出(或至少接近榜首)。

      【讨论】:

      • “需要注意的一点”+1“那么我会期待”-1
      • 你可能是对的。这假设有点过分了。感谢您的评论。
      • '看似并发的基准测试通常是连续的。例如,estone 基准是完全连续的。 “环基准”的最常见实现也是如此;通常一个进程处于活动状态,而其他进程在接收语句中等待。 erlang.org/doc/efficiency_guide/processes.html#id66266
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-28
      • 2011-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多