Erlang vs CERL 简介

Erlang众所周知,这里不介绍了。其优势在于:

  • 最简洁精练的分布式模型
    • Node, Process, Mail (Message)
  • 最优雅的错误处理模型:速错(Fail fast)
    • 如果出现任何异常,立即死掉
  • GenServer编程框架
    • 程序代码风格完全一致,便于交流
  • 轻量级的进程
    • 可以尽可能地按照正常的业务逻辑去设计,而不是过多地考虑硬件环境的制约。
  • 热部署(Hot swap)
  • 变量不可变
    • 更容易写出可靠的程序。也利于事务性代码的编写。
    • 当然这是一把双刃剑。它也改变了你的编程习惯。
CERL 这个词的来源是因为他被定为为:Erlang Model for C++。目的是在C++中获得Erlang的好处(部分)。不过,实际上CERL被实现为与语言无关的。基于CERL,你可以用PHP、Python之类的语言来写服务器或客户端。
CERL 基于Erlang的分布式模型。实现了Erlang做最重要的几个概念:Node, Process, Mail (Message)。他也支持速错(Fail fast)及GenServer编程框架。当然,也有它没有做到的,如:
  • CERL 不支持轻量级的进程。尽管CERL的Process模型和Erlang一致,但是他并不轻量,事实上CERL的进程就是操作系统中的Thread。刚开始我准备用协程,不过后来被证明这是不必要的,所以CERL永远都不考虑协程这东西。
  • CERL 不支持热部署。当然,这是指他没有提供机制支持,而不是指你没法做到。

为什么是CERL,而不用Erlang?

刚开始我确实用Erlang,而且完成了DEMO。不过,我最终发现这中间存在些问题。尽管Erlang的思想是非常优秀的,但是:

  1. Erlang是小众语言,使用它存在维护上的风险。(这个是缺点,但不是我最重要的理由)
  2. Erlang的变量不可变,改变了程序员的思维习惯。
    • 我个人原则上认可变量应不可变带来的好处,但是允许特殊情形下的可变(例如for循环的自变量)。
  3. Erlang是动态语言。
    • 我个人认为大型工程都应该使用静态类型语言,以获得更好的代码质量和性能(静态类型语言更容易写出高质量少BUG的代码)。

其实,最终极的理由是第3条。

CERL简介

CERL对外表现为一个动态库(cerl.dll) + 一个编译器(sdlc)。逻辑上CERL分为两层,底层称为CERL Core,上层为GenServer框架。

  • CERL Core –表现为动态库cerl.dll。主要实现Erlang的分布式模型,及其他辅助基础设施。
  • GenServer框架。它主要定义了服务器接口描述语言: Server Description Language(SDL),并提供相应的编译器 sdlc 以生成:
    • 客户端如何调用该服务器的Proxy代码。
    • 服务器端Stub代码。
    • 服务器Impl文件的框架代码。

基于CERL的程序样例

假设我们要实现一个简单的HashServer。

首先,我们定义该服务器的接口(HashServer.sdl):

 

  1. module hasht;   
  2.   
  3. server HashServer   
  4. {   
  5.     HashServer(UInt32 bucket_count);   
  6.   
  7.     [id=1] put(UInt32 key, UInt32 value) -> ok;   
  8.     [id=2] get(UInt32 key) -> {ok, UInt32 value} | false;   
  9.     [id=3, async] stop();   
  10. }  
module hasht; server HashServer { HashServer(UInt32 bucket_count); [id=1] put(UInt32 key, UInt32 value) -> ok; [id=2] get(UInt32 key) -> {ok, UInt32 value} | false; [id=3, async] stop(); }

 

然后,sdlc编译它,生成 sdl_hasht.h 文件(Client调用需要的Proxy),HashServerStub.h,HashServerImpl.h。

Proxy, Stub文件是不建议编辑的,HashServerImpl.h文件才是你需要去填写真正实现代码的地方。当然生成的还有一个比较次要的文件:sdl_hasht_base.h,该文件放的是Client和Server端都需要的公用代码,也不需要编辑。

生成的 HashServerImpl.h 大体如下:

  1. #include “sdl_hasht_base.h”   
  2.   
  3. namespace hasht {   
  4.   
  5. class HashServerImpl : public HashServerBase   
  6. {   
  7. protected:   
  8.    cerl::Process* _self;   
  9.   
  10. public:   
  11.    HashServerImpl(cerl::Process* me, cerl::Int32 bucket_count) : _self(me) {   
  12.      cerl_register(me, cerl::g_str(“HashServer”));  // --> 这一句并非sdlc生成的。   
  13.    }   
  14.   
  15.   void cerl_call put(const cerl::RemoteProcess& from, _PutResult& result, cerl::UInt32 key, cerl::UInt32 value);   
  16.   void cerl_call get(const cerl::RemoteProcess& from, _GetResult& result, cerl::UInt32 key);   
  17.   void cerl_call stop(const cerl::RemoteProcess& from);   
  18.   
  19.   static cerl::PID cerl_call _start(cerl::Process* caller, cerl::UInt32 bucket_count);   
  20. };   
  21.   
  22. } // namespace hasht   
  23.   
  24. #include "HashServerStub.h"   
#include “sdl_hasht_base.h” namespace hasht { class HashServerImpl : public HashServerBase { protected: cerl::Process* _self; public: HashServerImpl(cerl::Process* me, cerl::Int32 bucket_count) : _self(me) { cerl_register(me, cerl::g_str(“HashServer”)); // --> 这一句并非sdlc生成的。 } void cerl_call put(const cerl::RemoteProcess& from, _PutResult& result, cerl::UInt32 key, cerl::UInt32 value); void cerl_call get(const cerl::RemoteProcess& from, _GetResult& result, cerl::UInt32 key); void cerl_call stop(const cerl::RemoteProcess& from); static cerl::PID cerl_call _start(cerl::Process* caller, cerl::UInt32 bucket_count); }; } // namespace hasht #include "HashServerStub.h"
注解:_start 函数已经帮你实现,你需要做的就是实现这里的put, get, stop三个函数。他们和普通的函数并无区别,多余的from参数表明了该请求来自哪个进程,一般情况下不需要用到该参数。
客户端调用代码示例如下:
  1. #include <sdl_hasht.h>   
  2.   
  3. int cerl_callback client(cerl::Process* self, cerl::Mail* param)   
  4. {   
  5.      cerl::UInt32 key = 23, value = 64;   
  6.      cerl::UInt32 const bucket_count = 100;   
  7.      hasht::HashServer server = hasht::HashServerImpl::_start(self, bucket_count);   
  8.     // hasht:: HashServer server = cerl::getproc(self, remotenode, cerl::g_str("HashServer"));   
  9.      {   
  10.          hasht::HashServer::_PutResult result;   
  11.          server.put(self, result, key, value);   
  12.         if (result != cerl::code_ok)   
  13.              error processing;   
  14.      }   
  15.      {   
  16.          hasht::HashServer::_GetResult result;   
  17.          server.get(self, result, key);   
  18.         if (result == cerl::code_ok)   
  19.                printf(“result = %d/n”, result.value);   
  20.         else if (result == cerl::code_false)   
  21.                printf(“not found!/n”);   
  22.         else  
  23.                error processing;   
  24.      }   
  25. }  
#include <sdl_hasht.h> int cerl_callback client(cerl::Process* self, cerl::Mail* param) { cerl::UInt32 key = 23, value = 64; cerl::UInt32 const bucket_count = 100; hasht::HashServer server = hasht::HashServerImpl::_start(self, bucket_count); // hasht:: HashServer server = cerl::getproc(self, remotenode, cerl::g_str("HashServer")); { hasht::HashServer::_PutResult result; server.put(self, result, key, value); if (result != cerl::code_ok) error processing; } { hasht::HashServer::_GetResult result; server.get(self, result, key); if (result == cerl::code_ok) printf(“result = %d/n”, result.value); else if (result == cerl::code_false) printf(“not found!/n”); else error processing; } }

注解:服务器可能由client启动(通过调用_start函数,不过这种情况比较少见),也可以通过CERL提供的命名进程NamedProcess)机制向远程节点获得(该机制和域名机制有点类似),如本例的注释所示。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值