Elixir: 编程语言的未来

这篇文章谈一谈最近火爆的 Elixir,同时说一下对编程语言选择的看法。同时作为 Erlang 发烧友,Elixir 不可不提。即使有了那么多编程语言 Elixir 也值得接触。本文主要分为以下四块内容,点击「阅读原文」查看完整文章!

  • 现在开始接触 Elixir
  • 对编程语言选择的一点看法
  • Elixir 的元编程 (meta programming) 和 DSL
  • 很多有用的链接

这里节选文章的第二部分,主要对Elixir的特性和生态进行了介绍。

对编程语言选择的一点看法

作为个语言发烧友,之前接触过 Java、Erlang、Scala、PHP、JavaScript、C#、C、Python、Ruby 等一大堆各种风格的编程语言。有人说,学那么多编程语言是想做”翻译”吗?其实事情并不那么简单。

不同的语言背后是风格截然不同的类库群、技术堆栈、生态和工具链。不同的语言针对了不同类型的问题。某些语言解决某些问题的成本会比其他语言低非常多。回归本质,学习编程语言还是为了低成本高效的解决实际的业务问题。

个人喜欢的编程语言风格

可以近实时更新变更

最好不需要长时间编译才能执行、应用启动快。

Java、 C 编译很慢,不适合频繁修改的项目。但是 PHP 、Node.js 修改即可见,可以极大提高开发效率。最好还能 hot-reload 就像很多前端工具一样,只要源码有一点变更,不需要刷新页面自动反应在浏览器中。Play framework 类似的自动加载功能也可以。

更进一步,能够在生产环境热加载就更好了,更新代码不影响用户。针对这一点,很多人乐了, PHP 默认就是这样的啊,部署后刷新 APC 缓存就可以实现。

这正是无状态、短链接的 HTTP 应用的优势,虽然随之而来的是性能相对降低更多 TCP 的开销,但是把问题变得简单很多。但是很多其他语言做到这点就很难了,比如大部分 Java 应用。

Elixir、Erlang 可以做到真正的任何情况下开着跑车换轮子。

关于热加载,见另一篇文章:编程开发常用的热加载工具。

支持并发执行

人们更习惯顺序执行的思路,并且大部分业务逻辑都是顺序执行的。但是为了降低延迟、提高性能,最好能在语言层面支持并发执行。比如,一个操作开始还未返回结果,就可以开始另一个操作。

这样调用远程 API 或者远程 RPC,耗时为最慢那一个操作的耗时。从这一点看,大部分流行语言都可以做到并发调用,但 PHP 难以做到。

轻量级执行进程或者线程

由于某些限制,某些业务逻辑不可避免的会因为大量计算、网络磁盘 IO 等占用一个执行进程或者线程。所以希望这个执行体能够尽量轻量级,很少的内存占用,很快的启动时间,很少的切换消耗,最好能在 IO 执行的时候自动让出计算资源。

并发和并行

我们更多关注并发,但是比较少关注并行。因为通过增加机器数量能抗住大量用户的请求比节省机器更加简单和迫切。

这也是很多互联网公司动辄几百台上千台服务器的现状。用户和请求量的多少由于业务逻辑的不同很难比较,只能比较机器数量了。

并发之进程模型

PHP 既是典型的这种模式。曾经见过某异步 PHP 框架 CS 高居不下,甚至比业务逻辑的 CPU 使用更高。

并发之线程模型

这种模型相对于进程模型好了很多,因为线程比进程轻量很多,创建、切换也快很多。

问题:线程和内核线程的关系为多对多,内核线程有限。能够调度的用户线程有限,无法充分利用多核性能。创建新线程消耗非常大。IO 阻塞无法释放计算资源。

每个 CPU 核心只能同时运行一个线程,多个线程之间需要切换调度(CS)。如果是 CPU 密集类型的计算,没有或者很少 IO 操作,最好启动 CPU 核心数量的线程。

但是如果有 IO 操作,比如 磁盘或者网络,多余 CPU 核心数的线程有效,因为 IO 操作的时候可以切换到其他线程执行 CPU 操作。

并发之 Fork-join 轻量级进程模型:

Fork-join 创建自己的进程池来执行小粒度的任务。

相对于 Erlang 那种真正的抢占式调度的 VM 实现或者操作系统的抢占式调度,Fork-join 模型非常简单,也意味着相比之下效率相对低。

Fork-join 针对计算密集操作设计,意味着无法告诉 F/J 框架你因为 IO 等待而释放一会儿计算资源。所以,一般需要将异步 IO 操作放到另外的线程池,FJ 只处理纯计算。

基于 Scala 的 Akka 既是这种模型。所以,假如处理不当, Akka 的 Actor 很容易阻塞执行线程,如果执行线程池的线程被耗光,整个应用将会僵死在那里。而 Erlang 则没有这个问题。

并发之 Erlang 轻量级进程模型:

VM 调度线程,将计算划分为非常小的执行单元。可以支持非常多的进程。IO 阻塞可以自动释放资源。真正的抢占式调度。

类型系统

静态类型可以避免很多失误。动态类型经常会出现不可预期的结果,这有悖于 UNIX 风格的最少意外原则。

动态类型可以让开发更加快速。强静态类型系统会执行很快,比如 Java,但是也可以在有必要的时候使用反射,比如很多 RPC 框架的实现 (当然也有更进一步的字节码修改技术)。

每个语言的类型系统都有自己的特点。

丰富的内置结构或者容器类

最好能够区分 Interface、Struct 和 Implementation。能够以比较统一的模式轻松的定义自己需要的结构体。

GC 系统

除非 Erlang 无可媲美的轻量级线程级别的 GC 。否则你要么需要记住和理解复杂的 GC 调优参数、要么像 PHP 那样过一段时间将进程杀掉重来。

元编程和 DSL 扩展性

在语法级别的抽象和封装更能提高开发效率。Elixr 中如何实现 DSL。

执行速度和性能

这点和并发并行模式、以及多核利用率密切相关。

UNIX 风格

简单说就是模块化;每个模块完成相对单一的功能、复制任务由多个模块组合完成。项目设计就像搭积木。不同模块之前的输入输出可以拼接。

另外就是极简风格。

依赖和库管理系统

这点 Node.js npm 是最好的依赖管理系统了,这样导致了 Node.js 社群库数量的爆发。因为创建和发布一个库实在是太容易了,找到需要的库也非常简单。

极大提高了开发效率。

打包和发布系统

最好能打包成单一文件,容易分发和部署。比如 Java 应用打包成 Fat Jar 包到处执行,或者 Golang 那样编译成单一文件。

日志系统

真实的项目、日志非常重要。之前的文章已经提到日志的重要性。所以好的内置日志系统或者比较统一高效的日志模式非常重要。

最好支持屏幕打印、写文件等等功能。这可能不能算一个编程语言的特性了,要看这个语言是不是有很好的日志类库。

Java 的 SLF 就是一个比较好的日志系统类库。

工具链

项目构建、编译、测试工具比较完善。

比如 Java、Scala 项目的 maven、sbt 。Erlang 项目可以用 rebar ,但是 Elixir 的 mix 友好的很多倍。

另外一个好的 REPL 命令行工具非常重要,因为这可以方便的侵入应用进行调试,或者测试一条代码片段。

比如 PHP 的 php -a, sbt, Clojure 的 lein, Erlang 的 erl, Elixir 的 iex 等等。

脚本执行

这是脚本语言的一大优势。小任务可以立刻创建一个脚本执行,而不需要修改、编译部署现有运行的应用。

这点对于小任务非常重要。Erlang 和 Elixir 都支持这样运行,escript 或者 Elixir 脚本。比如,连接到集群,读取状态或者进行一次性的数据操作,然后断开。

测试系统

最好有一种比较标准的单元测试模型。比如 Java、Node.js、Scala、Elixir 等等。

说了这么多,回到 Elixir。首先 Elixir 执行和 Erlang 没有任何差别。Erlang 的优点 Elixir 完全具备。比如:真正的抢占式调度;充分利用多核心并行执行;Actor 模型;监控树;透明的分布式;

极其高的稳定性;代码的热更新部署;函数式编程;模式匹配;等等。并且很多 Erlang 下工具也是可以直接使用。比如 entop 。

另外 Elixir 比 Erlang 多出的好处在于更加友好的语法、工具链、社群。很多之前写 Ruby 的开始写 Elixir,因为他们的语法最接近。

原文发布于微信公众号 - 星流全栈(MeteorFullStack)

原文发表时间:2016-06-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏不会写文章的程序员不是好厨师

记一次"诡异"的git merge错误

今天照常开发,在日常部署测试的时候进行git merge 竟然出现了"代码丢失"的情况,相当诡异,特此记录。

75230
来自专栏Golang语言社区

Go的单元测试技巧

本文为社区粉丝原创投稿,再次感谢作者DrmagicE的分享,欢迎大家在评论区留言和作者讨论,同时也欢迎大家踊跃投稿,分享您的golang语言学习经验!投稿邮箱地...

16030
来自专栏极客生活

七种武器之一口箱子Redis

江湖传言「在任何规模、任何类型的服务器项目中,都存在一些最适合用Redis存储的数据。」

11520
来自专栏张戈的专栏

WordPress发布文章主动推送到百度,加快收录保护原创

工作实在太忙,也没时间打理网站。最近公司额外交待了一些网站 SEO 方面的优化任务让我关注(这就是啥都要会、啥都要做的苦逼运维的真实写照了...)。 于是抽空看...

38460
来自专栏恰童鞋骚年

.NET Core微服务之基于Ocelot+Butterfly实现分布式追踪

  微服务的特点决定了功能模块的部署是分布式的,以往在单应用环境下,所有的业务都在同一个服务器上,如果服务器出现错误和异常,我们只要盯住一个点,就可以快速定位和...

16830
来自专栏coding

这一次,真正掌握composercomposer是现代PHP的基石初识composercomposer包管理规范

现代高级编程语言,依赖管理工具是必不可少的。Java有Maven,Python有pip,Nodejs有npm, 而在composer出现之前,PHP只有被广为诟...

22620

分布式内存中网格中的聚合

今天,我们看到越来越多的应用程序不再构建在关系数据库上,而是建立在分布式环境上。发生这种情况是因为它们需要可扩展性和高可用性,而且还需要能够提供高吞吐量和低延迟...

235100
来自专栏哲学驱动设计

“秒杀”心得

    本文记录对某网站A的秒杀活动编写秒杀器的经历和技术重点。 故事回顾     某日早上,朋友给我说最近A网站在开展秒杀活动,有IPad、IPhone,让大...

36680
来自专栏张善友的专栏

微软为“离线”做好准备:推出同步框架

微软推出他们称为微软同步框架(Microsoft Sync Framework)的同步平台,这一框架允许开发者创建离线式的应用、设备和服务,可以与任何应用的任意...

21750
来自专栏程序员宝库

后端说:只是你不懂怎么用 headers!

事情是这样的,上一个项目我们的后端提供的接口,一次性返回了所有数据给我,分页功能是前端自己完成的。

14670

扫码关注云+社区

领取腾讯云代金券