18

我阅读了 Joe Armstrong 的“Programming Erlang”,以及“n 核机器中的 n 倍速度”理论。在 Erlang 中进行多核编程的有效方法是使用大量进程(线程)。

我是一名 C++ 程序员,所以我很好奇在 C++ 中创建大量线程和在 Erlang 中创建大量进程之间的区别。我知道在 C/C++ 中处理线程并不容易。我也知道锁定/解锁会使系统变慢。但这也不是不可能的,对吧?

那么.. 为什么 Erlang 是一种多核友好的语言?仅仅是因为它易于编程吗?

我正在为 MMORPG 制作在线游戏服务器,这就是我对 Erlang 作为替代服务器语言感兴趣的原因。

(我已经读过这个问题,但我认为这不是我要找的问题。)

4

5 回答 5

26

它归结为线程进程

操作系统是专门设计的,因此每个“用户”都认为他们拥有整台计算机——这就是为什么你以用户 wwwrun的身份运行 apache。

程序员,作为程序员,开始重载这种范式,首先是每个人类用户运行多个“工作”。因为操作系统是为多个用户设计的,所以该架构的扩展上限反映了登录用户的扩展上限——这就是为什么 apache 将在 4,000 到 8,000 个用户时开始消亡的原因。

流程是一个成熟的范例(我的流程不会让你的流程崩溃)。但是,当我们开始看到线程的引入时,事情开始变得非常不同。在这里,我们的程序具有外部阻塞活动(在磁盘上等待、在 io 上等待、在内存上等待)希望能够一方面等待,另一方面工作,线程允许您这样做并克服两个问题:

  • 您无法获得足够的进程,因为操作系统无法处理它

  • 每个进程都很昂贵,因为在设计上,它为“用户”提供了操作系统的全部功能

线程的问题在于它们打破了进程设计的分离。我的线程可能会破坏您的线程 - 错误会传播。

Erlang 的不同之处在于许多方面。Joe Armstrong 的博士论文名为“在存在软件错误的情况下制作可靠的分布式系统”

可靠性意味着进程优于线程。问题是操作系统进程太“昂贵”,因为它们是为人类(你拥有机器)设计的,而不是为程序的并发单元设计的。在 Erlang VM 中,VM 具有多用户系统的全部功能(它在操作系统进程中运行),每个 Erlang 进程的并发能力要小得多——如果它想使用“大机器”的话与为它做这件事的虚拟机交谈。所以 Erlang 进程比操作进程(和线程)便宜得多。你只是产卵,产卵,产卵。开箱即用的 Erlang VM 从 2**8 个进程开始,但您可以将其增加到数百万个(如果您有足够的 RAM)。

此外,正如乔在他的博士论文第一部分的第一部分所说的那样,要拥有可靠的软件,您需要从两台计算机开始。使用 Erlang/OTP,在编写时您不知道您的软件将在哪台计算机上运行。Erlang/OTP 集群在运行时会分配你的计算工作。因此,Erlang 进程是本地分布式的,spawn()(Erlang for fork())和重启语义也是如此。

因为 Erlang 有自己的进程,所以它有自己的调度程序和自己的代码加载器/二进制格式(Erlang 可以解释或编译为本地二进制文件)。这会带来一系列额外的好处——在您编写 Erlang/OTP 应用程序之前,它已经可以将其二进制文件热交换出来,等等

因此,确保您可以使用 C++ 编写多线程应用程序 - 但您有责任防止错误传播和构建系统稳定性。

当然,您可以用 C 构建可靠的软件 - 看看 Erlang(VM 是用 C 编写的),重点是您为什么要这样做?在过去,公司编写自己的“操作系统”,您现在可以编写自己的操作系统,但您为什么要这样做?有数百万行健壮的测试代码“执行”,就像 Erlang/OTP 系统中有 150 万行健壮的测试代码“执行”一样。

使用 Erlang 就是使用其他人编写的东西,并且只构建使您的公司有效的部分。

于 2009-03-13T08:57:49.547 回答
15

不,这不是不可能的,但是 Erlang 确实让它变得更容易了。关键是不在进程之间共享状态。Erlang 通过它是一种函数式语言来实现这一点。该函数应该没有副作用,也不应该访问任何变量状态(除了在堆栈上传递的参数)。有了这些属性,系统中任何函数的计算都可以转移到另一个具有单独内存空间的处理器上,而 Erlang 会为你做这件事。Erlang 只需要复制函数的参数和内存空间之间的结果(注意:这并不适合所有类型的应用程序......需要对非常大的输入状态进行操作的函数可能会表现出性能复制该状态时出现问题)。

在 C++ 应用程序中简单地使用线程可能有不同的处理器(在多核系统中)试图同时访问相同的共享内存。然后系统必须做很多工作来确保与每个核心关联的本地缓存保持一致。这是您可能遭受巨大性能损失的地方。由于这个原因,当您拥有多个内核时,我们有一个应用程序在工作时会降低性能。事实上,我什至会说你最好将你的应用程序设计为只使用你需要执行异步 I/O 的线程,但你需要让进程做真正的工作而不被阻塞I/O,使用完整的进程。通过使用完整进程,您可以保证每个进程都有自己的内存空间,并且没有两个线程会同时使用相同的内存(当然,然后,您需要想出一种在这些进程之间进行通信的好方法)。使用这样的系统以及围绕管理状态和分发处理的规则,您可以获得与 Erlang 提供的类似的结果,但是您必须做很多 Erlang 已经为您做的基础设施工作。

于 2009-03-13T04:19:05.317 回答
3

上下文切换非常昂贵。Erlang 中没有。锁让传统程序开始思考接下来要执行哪个线程。这也是极其昂贵的。

于 2009-03-13T05:30:50.807 回答
2

Gordon Guthrie回答很棒。哪里有更大的差异是个人喜好。在我看来,Erlang 更大的不同在于可靠性和偶然的可扩展性。在 Erlang 中,您可以以自然的方式设计并发进程,而不会出现大的性能问题,这将是偶然的,可扩展的可分发的。大信息中存在陷阱,因此在大多数情况下,您的设计将是优雅的,并且无需特别注意即可运行良好。当你的设计优雅时,你犯的错误就会更少,它会更容易管理,顺便说一下,你可以用最少的努力进行分发和扩展,结果将是可靠的。

简而言之,在 Erlang 中,您可以设计与在 C++ 中不同的程序,因为您可以在没有大的性能问题的情况下做到这一点,并且无需付出很大的努力就能保证良好的可伸缩性和可靠性。没有人是完美的,但对于有趣的大量任务,Erlang 是最佳选择。

编辑:关于 Erlang 和 C++ 之间差异的精彩介绍- Erlang 的顶级性能提高了 2.5 倍,延迟降低了 3 倍,SLOC 降低了 18 倍 - 我假设摩托罗拉的开发人员在 C++ 方面的经验足以编写好的软件。

于 2009-03-13T12:01:16.580 回答
1

好吧,具有只能设置一次变量的语言的性质以及它是一种函数式语言的事实会自动使具有大量并行性的程序能够以“正确的方式”编写和执行多核。

除了这两个事实之外,我对 erlang 了解不多,所以可能还有其他东西。但这并不是说您不能使 C++ 程序具有可扩展性,但您可能会经历很多事情来实现性能、可扩展性和稳定性,如果您使用 erlang 编写这些程序,这些都是免费的。

于 2009-03-13T03:17:37.990 回答