Erlang 入坑指南

程序君按:小山是一个很勤勉,求知欲很强的工程师,硬磕了不少 erlang 的底层实现 —— 前一段时间他搞懂了整个 erlang release 的过程,喜滋滋给我这种还活在 distillery 荫庇下的小确幸讲解。这篇文章是他在《程序人生》的处女稿,从另一个角度跟大家介绍一下 erlang。虽然我之前也也写过一篇介绍 上帝说:要有一门面向未来的语言,于是有了 erlang。但那篇过于笼统,没有专精一点,而他这篇,从六个基础函数讲起,深入浅出,拨开紫烟,把一座神秘美妙的香炉峰呈现在你的面前。 以下正文。


想了半天憋出这么个题目来,这也的确只是一篇入坑文。之前程序君写过一篇 Erlang 文章,我用谷歌翻译出来给 Joe Armstrong 老爷子看,老爷子看后大加赞赏,说这家伙搞懂 Erlang 了,我要和他约一组,于是就有了程序君与Joe老爷子对话这篇文章。这篇入坑指南很短,尝试从另一个角度认识 Erlang 。

Erlang 难吗?

难,也不难。

大部分人学习编程是从面向对象过来的。 Erlang 是一门函数式编程语言。写码时候的思维方式和传统的面向对象还是有很大差别的。这算是第一个挑战。

第二个挑战是, Erlang 的语法比较奇怪。当然这点因人而异,不过对于看惯了 Java / C++ / Ruby 的我们来说,第一次看见 Erlang 的程序是有些少许不适应。 Erlang 是 Joe 老爷子和他的两个同事 1986 年做的项目,受到一个叫做 Prolog 的语言的影响很深。Prolog 大部分人可能都没听过,更别说用过了,我特地搜了下 Prolog,跟 Erlang 绝对是一个亲妈生的。我问 Joe 为啥是 Prolog,老爷子说因为他 C 写特烂所以就用 Prolog 实现的初版 Erlang 。。。对于我来说, Erlang 的语法看着真是有点晕菜,所以一直特意没去碰它。不过之后用了一段时间 Erlang 之后,语法渐渐变得亲切可爱起来了,毕竟他只是一个语法,熟悉了就没那么可怕了。

接下来的挑战是并发。并发概念不难,但要把它搞对很难,尤其在 C 中。而并发在 Erlang 中巨简单,只要你理解了 Erlang 的核心(下面会讲)。我们的大脑会将我们不了解的东西无限放大,会觉得怎么都搞不定。但是一旦静下心来去了解,就会慢慢变得简单起来。

当我们花了很多时间熟悉函数式编程,看懂 Erlang 语法并且明白其并发模型后,一个词总是不停跳出来—— OTP。不论什么语言,总有其一套管用写法来写码。而 Erlang 的惯用写法就是OTP。绝大部分 Erlang 项目都会遵守这套设计模式,那么下一个挑战则是理解OTP这套设计模式,并且用这套设计模式来写 Erlang 代码。

又过了一段时间,当我们掌握了 OTP,写了很牛的 Erlang 程序,将其发布到生产环境中,然后服务器挂了,不得不调试找 bug,看erl_crash.dump。这时候会不可避免的发现必须要更深入了解 Erlang 的内核才能明白为啥会宕机——这个内核就是 Erlang 的虚拟机,也叫 BEAM。而这玩意是用 C 实现的,我去。

以上, Erlang 很难。即便是大牛,也要数月到几年的时间才能慢慢熟悉,甚至十年以上才能慢慢游刃有余。不过倘若真是钻研到这个境界, Erlang 也就不重要了。Joe老爷子说,他年轻时候写过太多代码了,他只花了30年时间来明白什么时候不去写代码,而是思考问题。大神的境界get不到~

但是,从另一个角度讲, Erlang 却很简单。 Erlang 其实是一门很小的语言,在某种程度上讲,我真希望 Erlang 能支持更多的语法糖和函数,这样写起平时的业务逻辑也能简单不少。Joe老爷子说,Erlang 的核心其实就是6个函数,真正搞懂它们,你就明白 Erlang 的世界观了。所以接下来,我们就来看看这6个函数。

了解 Erlang

Erlang 的世界中充满了进程,很多很多进程。我们暂时不用计算技术语,而是看看身边的世界。我们的世界充满了人,很多很多人。每个人都有一个大脑,里面包含了仅属于我们自己的记忆。我不知道你脑子里面在想什么,你不知道我脑子里在想什么,除非我问你,”约吗?“。你说:”约“。我们两个的记忆分别产生了些许变化。

从我们出生到现在,我们一直在维护大脑中的这份记忆,随着与外界的不断交互我们不停地在更新着这份记忆。我们学到很多与人打交道的方式,我们说话、写信、发短信、打电话。我们给别人留个字条,然后干自己的事去了;或者给人发个微信,然后接着上网吃瓜。这就是异步消息传递。


Erlang 的世界和我们的真实世界很像。每个 Erlang 进程维护着自己独有的内存,别的进程无法访问其内部状态,除非它们互发消息进行交流。所有的消息传递都是异步的,就像我们的现实世界。

听起来很简单吧!代码写出来啥样?

1> spawn(foo,hello,[]).
<0.70.0>

这样就会创建一个新的进程,调用foo:hello()。进程一旦执行完这个函数就会死掉,将所有分配到的内存还给BEAM。

如果你想创建两个进程同时做事,只需spawn两次:

1> spawn(foo,hello,[]).
<0.70.0>
2> spawn(foo,hello,[]).
<0.71.0>

这将创建两个进程并发调用foo:hello()。这就是 Erlang 的并发模型——也叫参与者模式 (Actor model)。

如果你想整100个进程同时做事,调用spawn 100次即可。简单粗暴。


现在我们知道如何创建进程,接下来是给它发消息。

1> Pid = spawn(foo,loop,[]).
<0.80.0>
2> Pid ! hello.
hello

这里我们启动一个进程调用 foo:loop()。我们假设这个loop函数会递归调用自己,这样我们的进程不会一下就死掉。spawn 会返回一个进程ID <0.80.0>,我们将其绑定到 Pid 变量中,并向其发个消息 hello。 Erlang 里用惊叹号 ! 发消息。好了,以上就是异步消息发送。这也是 Erlang 中两个进程之间交流的唯一手段。


当消息被发给某进程后,该进程如何收消息呢?

1> Pid = spawn(fun() ->
1>         receive
1>           hello -> io:format("Got hello message~n")
1>         end
1>       end).<0.86.0>
2> Pid ! hello.
Got hello message
hello

receive 来收消息。你可以在这里用模式匹配来匹配你想要接收的信息,忽略其他的消息。在这个例子中,我们只接收消息 hello


我们平时会记不住朋友的电话,所以我们用通讯录给电话号码加个名字。在 Erlang 中也没有必要记住每个进程的 Pid,给其注册个名字即可以后用名字来访问之。

1> Pid = spawn(fun() -> receive hello -> io:format("Got hello message~n") end end).
<0.93.0>
2> register(foo,Pid).
true
3> foo ! hello.
Got hello message
hello

只需调用 register(Name,Pid) 即可给任何进程注册名字。之后我们可以用该名字给进程发消息。


当我们给某进程注册了名字后,我们也能通过查找通讯录来找到其Pid。

1> register(foo,spawn(fun() -> receive hello -> hello end end)).
true
2> whereis(foo).
<0.102.0>

最后,一个进程可以通过调用 self() 来找到自己的Pid。

1> self().
<0.90.0>

以上6个函数就这么简单,再多也没有了。spawn, send, receive, register, whereisself。就这6个函数,组成 Erlang 的世界观。Joe老爷子说,理解 Erlang 并不需要去看多少项目或者代码,仅仅搞懂这几个函数就行了。他见过有些人写过上万行 Erlang 代码但是却没有真正理解 Erlang 的世界观。别这么做,从这些简单的函数入手。

Erlang 怎么学?

用个万用答案:因人而异。有人喜欢读书学,有人喜欢做个项目来学。

我个人一开始是接触 Elixir 。那会 Elixir 还很 young 很 simple, sometimes naive。我拜读了各种 Elixir 的书、博客、官方文档。做了不少项目,写了不少码,参加当地的 meetup,将所学的及时分享出去。将近一年到一个地步就是感觉也学了不少 Elixir 了但是感觉老少点啥。就像学开车我学遍全国各大驾校,但是当脚踩油门到车往前进这中间都发生啥事了还是一无所知。要想成为老司机就不得不要了解发动机的构造。而 Erlang 就是这个发动机。于是乎跳出舒适圈,看了两本 Erlang 经典,有幸见到作者还要了签名,飞到三番,向Joe老爷子本人求学 Erlang 。现在在看官方文档和源码,内中蕴含巨大财富。

我一直记得那个画面,在三月三番的那个阳光明媚的午后,Joe老爷子面带微笑,和蔼地描述着他所构建的 Erlang 世界观,简单又优美。当我越了解 Erlang ,就越能体会到这点。

希望你能透过这篇小文从另一个角度认识 Erlang 。其实 Erlang 很简单。

祝入坑愉快。

声明一下:本文所有收入都归小山同学所有。。。由于公众号奇葩的赞赏和原创设置,我只能把赞赏设成我自己,然后原创作者也成了我自己。。。这是逼着我自己来鄙视我自己的节奏啊。大家多多支持,好让小山同学多多发文!

原文发布于微信公众号 - 程序人生(programmer_life)

原文发表时间:2018-08-03

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序员互动联盟

【编程基础】谈谈C++语言--磨刀霍霍

看到上篇讲的《C++语言软件和编程》引发了大家的热议,小编很是激动。有人评论说C++是我们程序猿在虚拟世界的恋人,小编还真是暗暗欣喜了一下下--理解万岁!在此声...

37212
来自专栏编程一生

入我新美大的Java后台开发面试题总结

2016
来自专栏大数据文摘

Julia焦虑?这有份Facebook软件工程师的测试差评

近日,MIT CSAIL 实验室正式发布了 Julia 1.0,不少人称,该语言结合了C语言的性能和Python 的易上手性,被称为最聪明的一群大脑创造出的现...

1112
来自专栏Timhbw博客

就在今天,Swift 2.2 发布了!(iphone SE等也是)

2016-03-2213:12:19 发表评论 944℃热度 今天北京时间凌晨1点,iphone的春季发布会召开,可惜太晚,我熬不住,早上一起来必定是ipho...

2937
来自专栏张善友的专栏

LINQ在开发中的地位?

DLINQ *.dbml文件该属于哪一层,的确Linq to Sql存在问题,DLINQ中,虽然可以在语言层级定义查询逻辑。但是依然没有将数据库持久化数据映射为...

1966
来自专栏编程一生

大话高可用

1372
来自专栏张善友的专栏

Dynamic Language Runtime 微软打出的王牌

      Dynamic Language Runtime(DLR)。DLR和IronPython全部开源,如果你微软这样的动作吃惊,请看看Microsoft...

20410
来自专栏机器人网

11个这类开源名称的词源

  “它适用于信息目前掌握在少数人而非许多人手中的任何领域,少数人控制产品、服务或实体的生产、分发和改进的任何领域。”   我们已搞明白了这点,那么“Kuber...

3525
来自专栏BestSDK

一文看懂 iOS 11所有新功能:文件管理器、多任务处理、全新文件 App等

全新文件 App 通过这个App,可以把各类文件汇集在一起,浏览、搜索和整理文件。用户最近使用过的各种文件都会在一个专属的位置,以方便查看。除了 iPad 上的...

3288
来自专栏SDNLAB

SDN实战团分享(三十):Big Switch的技术颠覆

SDN的出现给了网络界一针强有力的“兴奋剂”,释放了网络界压抑已久的创新的能量。这一波技术思潮催生了大量的SDN创业公司,对各大厂商发起了巨大的冲击,网络领域的...

42710

扫码关注云+社区

领取腾讯云代金券