程序君按: 小山是一个很勤勉, 求知欲很强的工程师, 硬磕了不少 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 , whereis 和 self . 就这 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 很简单.
祝入坑愉快.
声明一下: 本文所有收入都归小山同学所有... 由于公众号奇葩的赞赏和原创设置, 我只能把赞赏设成我自己, 然后原创作者也成了我自己... 这是逼着我自己来鄙视我自己的节奏啊. 大家多多支持, 好让小山同学多多发文!
来源: http://www.tuicool.com/articles/yYvYFfn