Erlang进程与Java线程
我正在阅读SašaJurić的“Elixir in Action”一书,并在第一章中写道:
Erlang进程完全相互隔离。 它们不共享内存,并且一个进程崩溃不会导致其他进程崩溃。
Java线程也不是这样吗? 我的意思是,当Java线程崩溃时,它也不会崩溃其他线程 - 尤其是,如果我们正在查看请求处理线程(让main
线程免于此问题)
在我之后重复: “这些是不同的范例”
大声说出20次左右 - 这是我们目前的口头禅。
如果我们真的必须比较苹果和橙子,那么我们至少应该考虑“正在结果”的共同点在哪里相交。
Java“对象”是Java程序员的基本计算单位。 也就是说,一个对象 (基本上是一个具有胳膊和腿的结构,其封装比C ++更加严格)是你模拟世界的主要工具。 你认为“这个对象知道/拥有Data {X,Y,Z}
并且在它上面执行Functions {A(),B(),C()}
,随身携带Data
,并且可以通过调用与其他对象通信函数/方法被定义为它们的公共接口的一部分,它是一个名词,并且这个名词做了一些东西。“ 也就是说,您将围绕这些计算单位进行思考过程。 默认情况是,对象之间发生的事情是按顺序发生的,并且崩溃会中断该顺序。 它们被称为“物体”,因此(如果我们忽视艾伦凯的原始含义),我们会得到“物体定位”。
Erlang“进程”是Erlang程序员计算的基本单位。 一个过程 (基本上是一个在自己的时间和空间中运行的自包含的顺序程序)是Erlanger模拟世界的主要工具(1)。 与Java对象定义一个封装级别的方式类似,Erlang进程也定义了封装级别,但在Erlang情况下,计算单元完全相互隔离。 您不能在另一个进程上调用某个方法或函数,也不能访问其中的任何数据,也不能在任何其他进程的同一时间范围内运行一个进程,也不能保证相对的消息接收顺序到可能正在发送消息的其他进程。 他们可能完全处于不同的星球上(并且认为这实际上是合理的)。 他们可以相互独立地崩溃,其他流程只有在故意选择受到影响时才会受到影响(甚至包括消息传递:实质上是注册接收死亡流程中的遗书,本身并不保证以任何形式到达相对于整个系统的顺序,您可能选择或不选择作出反应)。
Java直接在复合算法中处理复杂性:对象如何协同工作来解决问题。 它旨在在单个执行上下文中执行此操作,并且Java中的默认情况是顺序执行。 Java中的多个线程表示多个运行上下文,并且是一个非常复杂的话题,因为不同定时上下文中的影响活动相互之间(以及整个系统:因此防御性编程,异常方案等)相互影响。 在Java中说“多线程”意味着与Erlang中的不同,事实上,这在Erlang中甚至从未说过,因为它始终是基本情况。 请注意,Java线程意味着隔离与时间有关,而不是内存或可见引用 - 通过选择什么是私有的和什么是公共的,手动控制Java中的可见性; 系统的普遍可访问元素必须设计成“线程安全”和可重入,通过排队机制顺序化,或采用锁定机制。 简而言之:调度是线程/并发Java程序中的手动管理问题。
Erlang根据执行时间(调度),内存访问和参考可见性分离每个进程的运行上下文,并通过完全隔离它来简化算法的每个组件。 这不仅仅是默认情况,这是这种计算模式下唯一可用的情况。 这样做的代价是,一旦处理序列的一部分跨越消息障碍,就不会完全知道任何给定操作的顺序 - 因为消息本质上都是网络协议,并且没有方法调用可以保证在给定的内部执行上下文。 这就类似于为每个对象创建一个JVM实例,并且只允许它们通过套接字进行通信 - 这在Java中是非常麻烦的,但是Erlang的设计工作方式就是这样(顺便说一句,这也是概念的基础如果人们放弃流行的词语往往会导致网页导向的包袱,那么编写“Java微服务”就成了一件大事 - Erlang程序默认为一群微服务)。 其全部是关于权衡。
这些是不同的范例。 我们可以发现的最接近的共同点是,从程序员的角度来看,Erlang进程类似于Java对象。 如果我们必须找到某种东西来比较Java线程......那么我们根本就不会在Erlang中找到类似的东西,因为在Erlang中没有这种类似的概念。 击败死马:这些是不同的范例。 如果你在Erlang编写一些非平凡的程序,这将变得很明显。
请注意,我在说“这些是不同的范例”,但甚至没有涉及OOP vs FP的主题。 “在Java中思考”和“在Erlang中思考”之间的区别比OOP和FP更为根本。
虽然Erlang的“面向并行的”或“面向过程”的基础更接近艾伦凯在创造“面向对象”这个术语时的想法(2),但这并不是真正的重点。 凯得到的是,人们可以通过将你的化合物切割成不连续的块来降低系统的认知复杂性,而隔离是必要的。 Java以一种使它在本质上仍然是基本程序性的方式来完成这个工作,但是围绕称为“类定义”的高阶调度闭包的特殊语法构造代码。 Erlang通过为每个对象分割运行上下文来实现这一点。 这意味着Erlang的东西不能互相调用方法,但Java的东西可以。 这意味着Erlang东西可以孤立地崩溃,但Java东西不能。 这种基本差异产生了大量的影响 - 因此是“不同的范式”。 权衡。
脚注:
绝对不是。 Java中的所有线程共享相同的地址空间,因此一个线程可能会垃圾其他线程拥有的东西。 在Erlang VM中,这是不可能的,因为每个进程都与其他进程隔离开来。 这是他们的重点。 任何时候你想让一个进程用另一个进程执行某些操作,你的代码必须向另一个进程发送消息。 进程之间共享的唯一东西是大的二进制对象,这些是不可变的。
Java进程实际上可以共享内存。 例如,您可以将相同的实例传递给两个独立的线程,两者都可以操纵其状态,从而导致潜在的问题,例如死锁。
另一方面,Elixir / Erlang通过不变性的概念来解决这个问题,所以当你将一些东西传递给一个进程时,它将是原始值的一个副本。
链接地址: http://www.djcxy.com/p/55251.html