【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

多核危机:Scala vs. Erlang

  • 2008-07-07
  • 本文字数:3548 字

    阅读完需:约 12 分钟

近来在博客上关于 Scala 与 Erlang 之间的争论越来越热。未来注定是多核的世界,问题在于如何去解决多核的危机。Scala 和Erlang 是两门渴望成为其解决方案的语言,但它们也有些许的不同。那么它们所采取的方式各有什么利弊呢?

引入问题

摩尔定律已经改变了。我们不再获得和以前一样的时钟频率增长,取而代之,我们得到了更多的(CPU)核心。今天,也许你的笔记本都已经是双核的了。

为了利用多核的特性,应用程序需要支持并发。如果你的客户买了一台八核的机器,要向他们解释清楚正常情况下应用程序只会用到12% 的CPU 能力将是一件费时费力的事,即便该机器是为该应用量身定制的。

在未来,情况可能变得更糟。你的顺序执行代码不仅不会跑得更快,甚至有可能实际上跑得更慢。其原因在于,你获得越多的核心,由于功耗和散热的影响,每个核心就会更慢。几年之后,英特尔就会给我们带来32 核的CPU ,按这种趋势,在我们不知不觉之中数千核的CPU 就会出现。但每个核心都会比现在的核心慢很多。

并发代码

一个显见的解决途径就是编写(或重写)软件以支持并发。最常见的方式莫过于使用线程,但大多数开发者都认为基于线程的应用编写起来特别的困难。死锁,饿死以及竞争条件对大多数并发开发者来说都是太熟悉的概念了。Erlang 和Scala 都大大减轻了这种痛苦。

语言概览

Scala 常被看作是下一个主要的JVM 语言。它结合了面向对象编程的范式和函数式编程的范式,与Java 相比有着更简洁的语法,它是静态类型的,有着跟Java 一样或者有时候更快的运行速度。有太多的理由值得去认真探索一下Scala。

Erlang 是一门为健壮性而生的语言,由于它的设计,它自然又是一门有着极好伸缩性的语言。它比Java 历史更早,但却常被看作引领未来并发的语言。它是一门动态类型的函数式语言,有着一些非凡的系统正常运行时间的成功例子。

争论核心

那么Scala 与Erlang 争论的到底是什么呢?说到底,就是性能表现与伸缩能力,但这争论也包括了其它像风格,语言特性以及库支持等等。这场争论开始于 Ted Neward 有一次无心的给出了他对几种语言的看法,并称“[Erlang] 在其自己解释器上运行事实上[是] 很差的”

Steve Vinoski 与 Ted 于是展开了几轮争论,但这一讨论很快转移到了更多的博客上,争论的焦点也转变成了 Scala 与 Erlang 之间那些有趣的差异和共同点。我们将总结每个有意思的论点并给出每种语言的利弊,并表达对一些问题的各种不同看法。

可靠性

Steve Vinoski 就 Ted 所发表的帖子进行了回应,给出了他对于“Erlang 在其自己解释器上运行”的感受

事实上,Erlang 在其自己解释器上运行得,很好很强大;如若不然,不可能有如此好的可靠性,它将只是又一个面向并发的有趣但却无用的语言实验而已。

Steve 谈到这个问题,就算一个语言本身可靠,它所依赖的基础也必须可靠才行。因为 Erlang 从骨子里就是为可靠性而设计的,从而支持并发,所以它不会受到一些并发性常见问题的影响,这主要是底层库包在并发环境下运行很好。

另一方面,Scala 是站在 JVM 之上的,所以一个重要卖点在于可潜在地使用所有现成的 Java 代码。然而,大部分的 Java 代码并非专为并发而设计的,使用 Scala 代码时要将此考虑进去。

轻量级进程

要运行大规模并发应用,你需要大量的并行执行。这可以通过几种方式达到。使用线程是一种常见的方式,使用进程又是另一种。其区别之处在于,线程与其它线程之间共享内存,而进程是相互独立的。这意味着线程需要像互斥信号这样的锁机制,防止两个线程在同一时间对同一内存进行操作,但进程不会受此问题影响,相反是使用一些消息传递机制来跟其它的进程间通信。但进程在性能和内存方面的代价是昂贵的,这正是人们就算知道基于线程的并发是一种极复杂的编程模型也宁愿选择它的原因。

Steve Vinoski 这样写到:

提供互不共享的轻量级进程架构将使得大规模并发能力变得十分容易,但这并不意味着一旦你设计好了,剩下的就只是编程的工作那么简单。

Erlang 采取了这样的并发方式。一个 Erlang 进程是非常轻量化的,Erlang 应用常常拥有成千上万的线程甚至更多。

Scala 通过基于事件的 Actor 从另一方面达到了同样的效果。 Yariv Sadan 解释说:

Scala 有两种类型的 Actor:基于线程或是基于事件。基于线程的 Actor 在重量级的 OS 线程内部执行。它们从不相互阻塞,但每个 VM 上可伸缩的 Actor 不会多于几千个。基于事件的 Actor 是简单的对象。它们是十分轻量化的,并且,像 Erlang 进程一样,因此它们可以在一台现代的机器上数以百万计的产生。

Yariv 解释到,尽管如此,这里面也还是有一些区别的:

与 Erlang 进程的区别之处在于,每个 OS 线程内部,基于事件的 Actor 是顺序执行的并且使用没有强占式调度算法。这使得一个基于事件的 Actor 可能在很长一段时间内阻塞其 OS 线程(甚至是无限的)。

不可变性

Erlang 是一门函数式语言。这意味着其数据是不可变的,像 Java 的 String 一样,并且没有副作用带来的风险。对数据的任意操作会产生一个该数据新的修改后的版本,但原数据仍然不变。在谈到健壮性的时候,不可变性是其需要高度注意的一个因素,因为没有代码可以无意间修改其它代码依赖的数据,但从并发的观点来看,不可变性也是一个十分重要的特性。如果数据不可变,其被两个并行执行路径更改的风险就不存在,因为没有办法改变它且不需要保持同步,所以数据可以被拷贝到其它机器上。

因为 Scala 构建在 JVM 之上,结合了面向对象和函数式方法的特点,它不具备像纯函数式语言的不可变性的保证。然而,在 Yariv 日志的评论部分,Yariv 和 David Pollack 就这两门语言之间的差别展开了一场有趣的讨论。David, Scala Web 框架 Lift 的作者,给出了他对于不可变性的看法:

不可变性 —— Erlang 强制了这一点,而且你几乎无法绕过它。但是,与强制一个单一类型相比,你可以用 Scala 神奇强大的类型系统的剩余部分去交换。我在进行 Scala Actor 编码时使用不可变数据,而让 Scala 的类型系统负责其它类型。

Yariv 问到:

只发送不可变类型难道不是一个重大限制吗?这意味着,例如,你不能从 Hibernate 装载一个简单的 bean 并将它发送给其它 Actor。

David 回答到:

我曾基于 Scala 的 Actor 构建个多个生产系统。实际上对于不可变性问题并没有多少工作需要处理。你只需要将你的相关类(消息)定义为不可变的,其它的就不用管了。

类型系统

Erlang 是动态类型的,而 Scala 是静态类型的并且相比 Java 有着更强的类型系统。然而,与 Java 相比最大的一个区别是 Scala 可以类型推断。这意味着你可以省掉大部分的类型注解,使得代码更加干净而编译器照样会做所有的检查。

关于动态与静态系统之间孰是孰非的争论看来永远也不会停止,但 Erlang 和 Scala 之间却有着显而易见的区别。

尾递归或是循环

Yariv 又提到:

函数式编程与递归从来都是形影不离的。实际上离开了尾递归你很难写出有用的 Erlang 程序,那是因为 Erlang 没有循环——它对一切都使用递归(这在我看来是一件好事 :))。

这显然使得 Erlang 与 Scala 产生了很大差别。Scala 提供了很多更传统的迭代,但 David Pollack 并没看出在这种环境下尾递归有什么优势:

尾递归——对基于事件的 Actor 来说根本不是什么问题。

如此说来,这仅仅有关你的偏爱和风格罢了。

热交换代码

由于 Erlang 是为可靠性而生的,热交换代码(运行时替换代码)是其内建的天性。

JVM 对热交换代码有所支持。类可以被改变,但由于其静态的类型系统,其方法签名是不可改变的——只有其内容可以改变。虽然有第三方工具致力于此,也有框架(提倡以一种使运行时更方便交换类的编程风格书写代码),但就算运行在JVM 上,如何进行交换仍是取决于你的Scala Actor 是如何构建的。Jonas Bonér 就此给出了一个详尽的例子

总结

Scala 和 Erlang 都是致力于解决多核危机的语言。它们来自不同的背景和年代,因此对待某些问题的方式也不尽相同,然而在许多方面它们的共识大于分歧,至少在并发性上如此。

Erlang 已经有着数十年的历史,并且已经在许多关键的真实系统中证明了自己。其不足之处在于它有一点像一个孤岛,最近的多语言编程的趋势似乎对Erlang 社区影响不大。

另一方面,Scala 是同一类型应用的新生儿。一些真实应用即将诞生,并且一些公司将未来押在了上面。Scala 相对Erlang 的最大优势在于,它运行在JVM 之上并且可以利用所有现成Java 代码、框架和许多工具。话虽如此,这种强大的能力也要求了更大的责任,因为大部分Java 代码不可能自动适应Scala 的Actor 模型。

对于主流语言无法帮开发者解决的压力越来越大的问题,两种语言都对提供了相似的解决途径。希望你在读完这篇争论总结之后,能更清楚哪种语言更适合你的特殊要求,并对其深入了解。

未来是多核的。Scala 和Erlang 将会越来越流行。

查看英文原文 The multicore crises: Scala vs. Erlang

2008-07-07 03:025338
用户头像

发布了 133 篇内容, 共 35.0 次阅读, 收获喜欢 1 次。

关注

评论

发布
暂无评论
发现更多内容

TiDB 7.1 LTS 发版:为关键业务提供业务稳定性和多租户场景支持

编程猫

TiDB pingCAP

中国银行开启数智人力管理新征途

用友BIP

人力资源 数智人力

“站在后天看明天”:华为给金融广厦架起数字栋梁

脑极体

金融 数字化 智能化

详解驱动开发中内核PE结构VA与FOA转换

华为云开发者联盟

开发 华为云 驱动开发 华为云开发者联盟 企业号 6 月 PK 榜

最强攻略 | 1分钟带你了解内测,成为BUG小能手!

百度Geek说

百度 测试 企业号 6 月 PK 榜 6 月 优质更文活动

苹果MR Vision Pro将会带动哪些零部件出货?

元器件秋姐

苹果 AR 交互 vr MR

技术赋能-混流编排功能,助力京东618直播重保 | 京东云技术团队

京东科技开发者

监控 直播技术 直播推流 企业号 6 月 PK 榜 重保

2022 中国开源创新大赛,时序数据库 TDengine 榜上有名

爱倒腾的程序员

涛思数据 时序数据库 ​TDengine

阿里云 EMAS & 魔笔:5月产品动态

移动研发平台EMAS

阿里云 DevOps 消息推送 低代码平台

理论+示例,详解GaussDB(DWS)资源管理

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟 企业号 6 月 PK 榜

主动发现系统稳定性缺陷:混沌工程 | 京东云技术团队

京东科技开发者

混沌工程 系统 系统工程 混沌工程实践 企业号 6 月 PK 榜

横空出世!京东技术专家狂推的Redis笔记,实战和原理两开花

程序知音

Java 数据库 redis Java进阶 后端技术

this 之谜揭底:从浅入深理解 JavaScript 中的 this 关键字(一)

控心つcrazy

JavaScript this指针 this

黑盒不黑:跨端 C/C++ 库一键源码调试方案

阿里技术

调试

软件测试 | Selenium验证页面元素

测吧(北京)科技有限公司

测试

SpringBoot 升级所踩过的坑 (二)

技术小生

6 月 优质更文活动

GreptimeDB v0.3 正式发布|分布式能力全面提升

Greptime 格睿科技

数据库 rust 云原生 分布式数据库 时序数据库

软件测试 | Web自动化测试

测吧(北京)科技有限公司

测试

Mybatis的parameterType造成线程阻塞问题分析 | 京东云技术团队

京东科技开发者

mybatis CPU告警 企业号 6 月 PK 榜 线程阻塞

2023年数智人力管理不容错过的2大神器

用友BIP

人力资源 数智人力

服务型企业为什么要做财务共享中心?

用友BIP

Postman 前后端都适用吗?

Liam

前端 后端 开发 Postman API

AI老师的作者:17岁的高中生,可能是你想要孩子成为的样子

无人之路

AI 教育 ChatGPT

揭秘阿里云Flink智能诊断利器——Fllink Job Advisor

阿里云大数据AI技术

大数据 flink 企业号 6 月 PK 榜

【Clickhouse】ReplaceingMergeTree引擎final实现合并去重探索 | 京东云技术团队

京东科技开发者

OLAP final clickhosue 企业号 6 月 PK 榜 合并去重

不愧是阿里P8出手的并发编程笔记!颠覆了我以往"正确"的认知

程序知音

Java 并发编程 java架构 Java进阶 后端技术

世界500强潍柴动力携手用友BIP全球司库打造资金管理系统,正式启动!

用友BIP

全球司库

Kubernetes 集群管理:Kurator or Kubespray

华为云开发者联盟

云原生 后端 华为云 华为云开发者联盟 企业号 6 月 PK 榜

NFTScan 成为 CMC 官方 NFT 数据合作伙伴

NFT Research

crypto NFT

金融集团企业资金管理难度加倍,用友BIP如何破解这个难题?

用友BIP

资金管理

祝贺!Databend 入选 ICT 中国可信云优秀云原生创新案例

Databend

多核危机:Scala vs. Erlang_Java_Niclas Nilsson_InfoQ精选文章