我对 Erlang 编程理念的理解:以分布式架构师的角度写代码。
函数式编程
Erlang 里面的函数是数学里面的函数:必须有返回值。 只要是函数必然有返回值,函数是一个过程,以英文的句号为函数结束符。 函数结束之前的表达式就是该函数的返回值。 所以这也是在 Erlang 里面的函数不会看到任何 return 语句的原因。 C++ 等其他语言的函数和函数之前可以通过共享变量来实现消息传递。 Erlang 里面的函数不可以,消息的传递通过函数的传入和传出。 也只是为什么 Erlang 号称天生之处并行处理的原因, 因为他们不共享变量,也就不需要加锁。
很多人听到函数式编程都会觉得高大上或者晦涩难懂。 因为函数是编程没有 for 循环语句, 但是在我看来,关键在于会使用【列表推倒】和【尾递归】来进行循环遍历。 说到函数式编程就会拿快速排序说事,下面这个示例是 Erlang 版本的快速排序:
-module(sort).-export([qsort/1]).
qsort([]) -> []; qsort([Pivot | T]) -> qsort([X || X <- T, X < Pivot] ++ [Pivot] ++ qsort([X || X <- T, X >= Pivot]).
[X || X <- T, X < Pivot]
很多人一直在鼓吹函数式语言马上就要迎来朝阳, 但是在我看来,函数式编程永远只能是小众语言, 这就像当年的 lisp machine ,被鼓吹的天花乱坠还是夭折了。 现在主流的计算机架构都是冯诺依曼体系的,并不是最适合函数式语言的生存土壤。
一切都是常量
没有变量,也就没有通过变量共享状态导致的资源竞争,也就不需要加锁。 任何状态的变化都是通过函数的输入输出来进行改变, 轻量级进程的状态变化也是靠消息传递(函数的输入输出)来实现。 这也是为什么有人说函数式编程适合高并发的原因,因为他们没有变量, 一切都是常量。
轻量进程
Erlang 里面有 spawn 函数,可以快速的创建一个 process , 这里的 process 不是操作系统的进程,而是 Erlang 自己的轻量进程。 Erlang 轻量到超乎你想象, 构建 kv 数据库的时候,甚至可以对不同的 key 分配给不同的进程。 而且进程的表示单位是 Pid ,只要知道进程的 Pid, 哪怕该进程是在别的机器上面,都可以很轻易的发送给它。 原因是 Erlang 的【天生自带RPC通信】和【自带端口映射】
天生自带RPC通信
ToPid ! Data
Pid ! {name, "jb51.net"}.
进程端口映射
节点之间发消息在代码里面的表示也还是
ToPid ! Data
Epmd是Erlang Port Mapper Daemon的缩写,在Erlang集群中相当于dns的作用,供给节点名称到端口的查询办事,epmd绑定在总所周知的4369端口上。
有了 epmd ,写分布式程序就好像写单机程序一样简单。
严密的模块化管理
Erlang 的模块类似 C++ 中的 namespace(命名空间),但是比命名空间更利于高效的软件工程管理。
在 Erlang 项目源码中处处可见如下代码。
-module(my_app). -export([start/2, stop/1]).
-module 指明模块名,-export 指明导出的函数。 未被导出的函数都无法被外界调用。 从软件工程上看的话,这样使得模块功能和使用方法更加清晰。 使用者只需要关心如何 -export 里面的函数即可。 相比较之下 C++ 对这方面特别不规范,而 Java 通过对类声明为 public class 指明可以被外界使用, Node.js 也是使用 export 来显示声明可以被外界使用的函数。
行为模式
-module(ecomet_app).-behaviour(application).
%% comment: Application callbacks -export([start/2, stop/1]). -behavior(application).
Erlang/otp 里面的【行为模式】概念等价于 OOP 里面的接口概念。 上面代码示例的意思就是该模块(ecomet_app)遵守的行为模式是(application)。 刚行为模式需要实现的两个接口函数就是 -export([start/2, stop/1]). 。
另一个示例如下是遵守监督者(supervisor)行为模式, 实现的一个接口函数是 -export([init/1]). 。
-module(ecomet_sup).-behaviour(supervisor).
%% Supervisor callbacks -export([init/1]).
监督者机制
Erlang/otp 的天生分布式特性在监督机制里面体现的很好, 每一个 otp 应用启动的时候,都是启动监督者(supervisor)和工作者(worker)。 他们的关系是树形结构,每个工作者的上级都会有监督者, 每个监督者的上级也可能有监督者。 当工作者异常退出的时候,监督者会根据相应的参数决定是否对工作者进行重启。 如果重启失败的话监督者也会退出,而更加上层的监督者收到信号后会对他们进行重启等处理。 这个监督者机制非常好理解,其实就是 OOP 编程里面的 try ... catch 异常处理机制。 当出现异常的时候一层一层的往上抛出,直到有人重启。
otp平台
Erlang 最强大的地方也是最让我感觉难学的地方,就是它的 otp 平台。 各种行为模式, 让我感觉就像多年以前学习 MFC 的时候, 感觉很强大,但是却总是感觉自己被按死在一条特定的轨道上面奔跑, 有种不自由的疲惫感。
代码热切换
热切换也叫热升级,大部分情况下,如果需要对 C++/Java 程序进程版本升级, 则需要重启进程。 Erlang 支持热切换的意思就是可以在运行的时候进行代码升级。 升级过程不影响进程的运行, 而且在过渡阶段新旧版本还可以共存。 是不是碉堡了。这个功能对于那些需要 7x24 高可用的服务来说简直就是爽爆了。
Erlang 进程本身可以通过一个类似“后门”的控制台 erl 来实时的查看状态, 甚至直接使用控制台来修改配置等,非常方便,这对于大部分其他语言来说, 简直就是黑魔法般神奇的存在。
典型缺点
1.文档太少,出现问题搜索出来的答案也少。
2.Erlang 人才稀缺,招聘不易。
3.动态语言最典型的就是调试不易。
4.上手门槛较高。
最后,我只是 Erlang 的入门初学者, 因为工作中需要使用 ejabberd (Erlang 的开源项目), 从而学习了 Erlang , 欠缺实战经验,所以这篇文章标题起为 【Erlang初体验】。
本文向大家介绍Erlang的一些编程技巧分享,包括了Erlang的一些编程技巧分享的使用技巧和注意事项,需要的朋友参考一下 guard guard可以以逗号或者分号分隔,以逗号分隔表示最终的结果为各个guard的and结果,以分号则是只要任意一个guard为true则最终结果为true。 guard在list comprehension中可以筛选元素: guard中不能使用自定义函数,因为guar
本文向大家介绍Erlang中的Record详解,包括了Erlang中的Record详解的使用技巧和注意事项,需要的朋友参考一下 在Erlang内部只有两种混合的数据类型:List和Tuple,而这两种都不支持命名访问,所以如果没有额外的库的话想创建像PHP、Ruby或Python中的关联数组(Ruby中的Hash)是不可能的 在Ruby中我可以这样做: 在Erlang的语法级别不支持这种表达 为了
本文向大家介绍Erlang中的匹配模式总结,包括了Erlang中的匹配模式总结的使用技巧和注意事项,需要的朋友参考一下 一、赋值时匹配 原子匹配 变量匹配 元组匹配 列表匹配 参数匹配 记录匹配 比特匹配 二、流程控制中的匹配 if case try catch 消息传递匹配
Erlang shell 被用于表达式的测试。因此,测试可以在 shell 进行,这是在实际的应用程序运行之前进行测试。 下面的例子展示了如何在 shell 中添加表达式并使用。这里需要指出的是,表达需要使用(.)定界符来作为结束符。 执行该命令后,shell 打印出另一个提示,此时为命令编号为2(因为指令数在每次输入新命令后增加)。 以下函数在 Erlang Shell 最常见的。 b() −
Erlang 版本的 socket.io 服务器实现
maestro 是 Erlang 池管理程序。 为什么? 短暂 I/O 任务(比如数据库访问)的大型 worker 池会因为太多迁入和迁出活动而拖垮单个 poolboy 管理器。 怎样做? 使用简单的方法,启动多个池;随机迁出。maestro 需要了解每个池的工作流,当每个池都是同一类型的加载模式时,将会提升复杂性,降低性能,没有什么明显的优势。 使用: MaestroName = many_po