我正在阅读 "Elixir in Action" book by Saša Jurić, and in the first chapter它说:
Erlang processes are completely isolated from each other. They share no memory, and a crash of one process doesn’t cause a crash of other processes.
Java 线程不也是这样吗?我的意思是当 Java 线程崩溃时,它也不会崩溃其他线程 - 特别是,如果我们正在查看请求处理线程(让我们从本讨论中排除
main
线程)
最佳答案
在我之后重复: “这些是不同的范式”
大声说 20 次左右——这是我们目前的口头禅。
如果我们真的必须比较苹果和橙子,那么至少让我们考虑一下“作为水果”的共同方面在哪里相交。
Java“对象”是Java程序员的基本计算单位。也就是说,一个 对象 (基本上是带有封装的 ARM 和腿的结构 somewhat more strictly enforced than in C++ )是您建模世界的主要工具。你认为“这个对象知道/拥有 Data {X,Y,Z}
并对其执行 Functions {A(),B(),C()}
,携带 Data
无处不在,并且可以通过调用定义为公共(public)接口(interface)一部分的函数/方法与其他对象通信。它是一个名词,而这个名词确实有作用。”。也就是说,您围绕这些计算单位来确定您的思维过程。默认情况下,对象之间发生的事情按顺序发生,崩溃会中断该顺序。它们被称为“对象”,因此(如果我们忽略 Alan Kay 的原始含义)我们得到了“面向对象”。
Erlang“进程”是 Erlang 程序员的基本计算单元。一个 流程 (基本上是在自己的时间和空间中运行的自包含顺序程序)是 Erlanger 对世界进行建模的主要工具(1)。类似于 Java 对象定义封装级别的方式,Erlang 进程也定义了封装级别,但在 Erlang 的情况下,计算单元彼此完全切断。您不能在另一个进程上调用方法或函数,也不能访问其中的任何数据,一个进程甚至不能在与任何其他进程相同的时间上下文中运行,并且无法保证消息接收的顺序相对到可能正在发送消息的其他进程。它们也可能完全位于不同的行星上(而且,想想看,这实际上是合理的)。它们可以彼此独立地崩溃,而其他进程只有在它们有意选择受到影响时才会受到影响(甚至这也涉及消息传递:本质上是注册以接收来自死进程的遗书,而遗书本身并不能保证以任何形式到达相对于整个系统的顺序,您可能会也可能不会选择对此使用react)。
Java 直接在复合算法中处理复杂性:对象如何协同工作来解决问题。它旨在在单个执行上下文中执行此操作,Java 中的默认情况是顺序执行。 Java 中的多线程表示多个运行上下文,并且是一个非常复杂的主题,因为不同时序上下文中的 Activity 会相互影响(以及整个系统:因此,防御性编程、异常方案等)。在 Java 中说“多线程”的含义与在 Erlang 中不同,事实上,在 Erlang 中甚至从未说过这一点,因为它始终是基本情况。请注意,Java 线程意味着与时间相关的隔离,而不是内存或可见引用——Java 中的可见性是通过选择什么是私有(private)的和什么是公共(public)的来手动控制的;系统中普遍可访问的元素必须被设计为“线程安全”和可重入的,通过排队机制进行排序,或者使用锁定机制。简而言之:调度是线程/并发 Java 程序中手动管理的问题。
Erlang 在执行时间(调度)、内存访问和引用可见性方面将每个进程的运行上下文分开,这样做通过完全隔离来简化算法的每个组件。这不仅仅是默认情况,这是该计算模型下唯一可用的情况。这是以永远不知道任何给定操作的确切顺序为代价的,一旦您的处理序列的一部分跨越了消息屏障——因为消息本质上都是网络协议(protocol),并且没有方法调用可以保证在给定的时间内执行语境。这类似于为每个对象创建一个 JVM 实例,并且只允许它们通过套接字进行通信——这在 Java 中是非常麻烦的,但这就是 Erlang 的工作方式(顺便说一句,这也是概念的基础如果人们抛弃了流行语往往包含的面向 Web 的包袱,那么编写“Java 微服务”的过程就变得如此——默认情况下,Erlang 程序是一大群微服务)。一切都与权衡有关。
这些是不同的范式。我们能找到的最接近的共同点是,从程序员的角度来看,Erlang 进程类似于 Java 对象。如果我们必须找到一些东西来比较 Java 线程......好吧,我们根本不会在 Erlang 中找到类似的东西,因为在 Erlang 中没有这样的可比概念。打败一匹死马:这些是不同的范式。如果你用 Erlang 编写一些重要的程序,这将变得显而易见。
请注意,我说的是“这些是不同的范式”,但我什至没有触及 OOP 与 FP 的话题。 “在 Java 中思考”和“在 Erlang 中思考”之间的区别比 OOP 与 FP 更根本。 (事实上,我们可以为 Erlang VM 编写一种像 Java 一样工作的 OOP 语言——例如: An implementation of OOP objects in Erlang 。)
虽然 Erlang 的“面向并发”或“面向过程”的基础确实更接近 Alan Kay 在创造术语“面向对象”(2) 时的想法,但这并不是真正的重点。 Kay 的意思是,可以通过将您的计算机切割成离散的块来降低系统的认知复杂性,并且隔离是必要的。 Java 以某种方式实现了这一点,它本质上仍然是过程性的,但围绕称为“类定义”的高阶调度闭包的特殊语法来构建代码。 Erlang 通过拆分每个对象的运行上下文来实现这一点。这意味着 Erlang 的东西不能互相调用方法,但 Java 的东西可以。这意味着 Erlang 的东西可以单独崩溃,而 Java 的东西不能。大量的含义源于这种基本差异——因此是“不同的范式”。权衡。
脚注:
关于java - Erlang 进程与 Java 线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32294367/