Fork me on GitHub
随笔 - 215  文章 - 13  trackbacks - 0
<2016年12月>
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567


专注即时通讯及网游服务端编程
------------------------------------
Openresty 官方模块
Openresty 标准模块(Opm)
Openresty 三方模块
------------------------------------
本博收藏大部分文章为转载,并在文章开头给出了原文出处,如有再转,敬请保留相关信息,这是大家对原创作者劳动成果的自觉尊重!!如为您带来不便,请于本博下留言,谢谢配合。

常用链接

留言簿(1)

随笔分类

随笔档案

相册

Awesome

Blog

Book

GitHub

Link

搜索

  •  

积分与排名

  • 积分 - 204453
  • 排名 - 126

最新评论

阅读排行榜

Erlang初学:Erlang的一些特点和个人理解总结
http://www.jb51.net/article/61047.htm

我对 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]).


非常简洁,[Pivot | T] 就是拿列表的第一个元素当快排中的 Pivot 。
复制代码 代码如下:

[X || X <- T, X < Pivot]

上式就是【列表推导】, 含义就是找出列表 T 中所有元素小于 Pivot 中的元素组成一个新的列表。 不过,这个例子显然性能不高,只是一个示例。

 

很多人一直在鼓吹函数式语言马上就要迎来朝阳, 但是在我看来,函数式编程永远只能是小众语言, 这就像当年的 lisp machine ,被鼓吹的天花乱坠还是夭折了。 现在主流的计算机架构都是冯诺依曼体系的,并不是最适合函数式语言的生存土壤。

一切都是常量

没有变量,也就没有通过变量共享状态导致的资源竞争,也就不需要加锁。 任何状态的变化都是通过函数的输入输出来进行改变, 轻量级进程的状态变化也是靠消息传递(函数的输入输出)来实现。 这也是为什么有人说函数式编程适合高并发的原因,因为他们没有变量, 一切都是常量。

轻量进程

Erlang 里面有 spawn 函数,可以快速的创建一个 process , 这里的 process 不是操作系统的进程,而是 Erlang 自己的轻量进程。 Erlang 轻量到超乎你想象, 构建 kv 数据库的时候,甚至可以对不同的 key 分配给不同的进程。 而且进程的表示单位是 Pid ,只要知道进程的 Pid, 哪怕该进程是在别的机器上面,都可以很轻易的发送给它。 原因是 Erlang 的【天生自带RPC通信】和【自带端口映射】

天生自带RPC通信

复制代码 代码如下:

ToPid ! Data

ToPid 是接受方进程的id , Data 可以是 Erlang 的任何类型,比如
复制代码 代码如下:

Pid ! {name, "jb51.net"}.

也就是可以直接把任何数据结构当成消息发送,天生自带 RPC 通信。 (虽然本来 RPC 的含义是“远程过程调用”,不过其实反正就是帮你序列化了数据结构,Erlang 的 ! 操作符也是如此。)

 

进程端口映射

节点之间发消息在代码里面的表示也还是

复制代码 代码如下:

ToPid ! Data

也就是在写代码的时候,根本不用考虑该进程是在哪台机器上面, 无论是本 Erlang 进程(这里的进程是操作系统级别的进程,不是 Erlang 的轻量进程) 内, 还是其他机器的进程,都不用管。 这是因为有 epmd 的存在。

 

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初体验】。

http://www.jb51.net/article/61869.htm

这篇文章主要介绍了Erlang中的OTP简介,OTP包含了一组库和实现方式,可以构建大规模、容错和分布式的应用程序,包含了许多强大的工具,能够实现H248,SNMP等多种协议,需要的朋友可以参考下

OTP包含了一组库和实现方式,可以构建大规模、容错和分布式的应用程序,包含了许多强大的工具,能够实现H248,SNMP等多种协议,核心概念是OTP行为,可以看作一个用回调函数作为参数的应用程序框架,类似一个J2EE容器。行为负责解决问题的非函数部分,回调函数负责解决函数部分。
 
通过gen_server模块可以实现事物语义和热代码交换,

1)      确定回调模块名
2)      编写接口函数
3)      在回调模块里编写6个必需的回调函数

当服务器崩溃时,需要一种机制来检测并重启它,要用到监测树,即创建一个监控器来管理服务器。监测树有两种:一对一和一对多。

复制代码 代码如下:

$erl –boot start_sasl

会创建一个运行生产系统的环境,系统架构支持库(SASL,System Administration Support Libriaries)将负责错误记录和过载保护等工作。
 
使用gen_server, gen_supervisor,application等行为,可以构建可靠性为99.9999999的系统。
统一化的erlang消息:

 

1)  抽象了不同线路协议之间的区别
2)  Erlang消息无需解析,接收进程不必先解析消息再处理,而http服务器就必须解析就收到的所有消息
3)  Erlang消息可以包含任意复杂度的数据类型,而http消息必须被序列化成扁平化才能传输
4)  Erlang消息可以在不同处理器之间传送

常见的第三方库有rebar(https://github.com/basho/rebar)和cowboy(https://githun.com/extend/cowboy)。 Rebar是管理erlang项目的事实标准,用户可以通过rebar创建新项目、编译项目、打包它们,以及把它们与其他项目整合在一起,同时集成了github。Cowboy是一个用erlang编写的高性能web服务器,是嵌入式web的热门实现。另外,库mochiweb2(http://github.com/mochi/mochiweb)的编码和解码方法可以实现json字符串和erlang数据类型的相互转换。
 
Erlang程序在多核CPU上运行

1)  使用大量进程
2)  避免副作用,例如不使用共享式ETS或DETS
3)  避免顺序瓶颈,可以选择pmap代替map
4)  小消息,大计算
5)  用mapreduce使计算并行化
mapreaduce是一个并行高阶函数,定义如下

复制代码 代码如下:

-specmapreduce(F1,F2,Acc0,L) ->Acc
         F1 = fun(Pid,X) ->void
         F2 = fun(Key,[Value],Acc0) ->Acc
         L = [X]
         Acc = X =term()

Mapreduce 是在并行高阶函数(phofs)模块中定义的。

 


http://www.jb51.net/article/61870.htm
这篇文章主要介绍了Erlang中的socket编程简单例子,本文给出了TCP服务器echo示例、Tcp 的echo客户端示例、UDP server示例、UDP client 示例,需要的朋友可以参考下

Erlang 中gen_tcp 用于编写TCP程序,gen_udp用于编写UDP程序。一个简单的TCP服务器echo示例

复制代码 代码如下:

Start_echo_server()->
         {ok,Listen}= gen_tcp:listen(1234,[binary,{packet,4},{reuseaddr,true},{active,true}]),
         {ok,socket}=get_tcp:accept(Listen),
         gen_tcp:close(Listen),
         loop(Socket).
 
loop(Socket) ->
         receive
                  {tcp,Socket,Bin} ->
                            io:format(“serverreceived binary = ~p~n”,[Bin])
                            Str= binary_to_term(Bin),
                            io:format(“server  (unpacked) ~p~n”,[Str]),
                            Reply= lib_misc:string2value(Str),
                            io:format(“serverreplying = ~p~n”,[Reply]),
                            gen_tcp:send(Socket,term_to_binary(Reply)),
                            loop(Socket);
                   {tcp_closed,Socket} ->
                            Io:format(“ServerSocket closed ~n”)
         end.

Tcp 的echo客户端示例:
复制代码 代码如下:

echo_client_eval(Str) ->
         {Ok,Socket} = gen_tcp:connect(“localhost”,2345,[binary,{packet,4}]),
         ok= gen_tcp:send(Socket, term_to_binary(Str)),
         receive
                   {tcp,Socket,Bin}->
                            Io:format(“Clientreceived binary  = ~p~n”,[Bin]),
                            Val=binary_to_term(Bin),
                            io:format(“Clientresult = ~p~n”,[Val]),
                            gen_tcp:close(Socket)
         end.

UDP server示例
复制代码 代码如下:

udp_demo_server(Port) ->
         {ok,Socket}= gen_udp:open(Open,[Binary]),
         loop(Socket).
Loop(Socket)->
         receive
                   {udp,Socket,Host,Port,Bin}->
                            BinReply= …,
                            gen_udp:send(Socket,Host,Port,BinReply),
                            loop(Socket)
         End.

UDP client 示例:
复制代码 代码如下:

udp_demo_client(Request) ->
         {ok,Socket}= gen_udp:open(0,[Binary]),
         ok= gen_udp:send(Socket,”localhost”,1234,Request),
         Value=    receive
                                     {udp,Socket,_,_,Bin}-> {ok,Bin}
                            after2000 -> error
                            end,
         gen_udp:close(Socket),
         Value

注意,因为UDP是不可靠的,一定要设一个超时时间,而且Reqeust最好小于500字节。
WebSocket, JS 和Erlang相结合,能够实现Web的绝大多数功能。
 
posted on 2016-12-19 11:49 思月行云 阅读(360) 评论(0)  编辑 收藏 引用 所属分类: Erlang

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理