320 likes | 749 Views
从 Erlang 到 CERL 到 Golang. 许式伟 xushiwei@qbox.net 2011-10-15. 内容概要. 历史 Erlang => CERL => Golang Erlang CERL Golang QBox (Q盘). 历史:ECUG 议题. Erlang 2007: 我为什么选择了Erlang? 2008: Erlang 与 Comet Programming CERL 2009: CERL: 谈谈“Boost.ASIO、Erlang与服务器编程” 2010: 架构之美 & 软件质量保障 Golang
E N D
从 Erlang 到 CERL 到 Golang 许式伟 xushiwei@qbox.net 2011-10-15
内容概要 • 历史 • Erlang => CERL => Golang • Erlang • CERL • Golang • QBox (Q盘)
历史:ECUG 议题 • Erlang • 2007: 我为什么选择了Erlang? • 2008: Erlang 与 Comet Programming • CERL • 2009: CERL: 谈谈“Boost.ASIO、Erlang与服务器编程” • 2010: 架构之美 & 软件质量保障 • Golang • 2011: 从 Erlang 到 CERL 到 Golang
历史:我为什么选择了Erlang? • Erlang 的优势 • Erlang解放的是程序员在并行处理上的困扰,这比内存管理的复杂度更大。 • 面向并发编程(OCP) • 错误处理哲学: 速错(Fail fast)
历史:我为什么选择了Erlang? • Erlang 的瓶颈 (困难之处) • 并行思维模式 • 尽管Erlang程序可以很方便地并行/分布式,但是这并不意味着并行思维模式不需要被理解和掌握。 • 缺乏深入人心的FP编程理论 • 没有FP“数据结构”学。大学的数据结构课程, 都是基于命令式语言的。 • 需要更高的培训成本 • 由于FP没有深入人心,Erlang亦仍然属于小众 语言,故此培训成本较高。
CERL • 最初语义 • Erlang Model for C++ • Erlang Style Concurrency(Erlang风格的并发模型)在传统语言中的实施 • CERL 2.0 • 编程范式与Erlang Style Concurrency有很大的差异,更接近于主流语言的编程范式。 • 更多资料参阅: • http://ecug.org/cerl
CERL 2.0 • 轻量级进程、进程间用消息传递通信 • 同 Erlang Style Concurrency • 同 Golang • 进程间通过MQ(Channel)通信 • 无进程邮箱(不同于Erlang) • 同 Golang • Socket/File IO 与轻量级进程完美结合 • 同 Golang,任何进程的 IO 不阻塞其他进程 • Message 是二等公民,Selective receive 是浮云 • 同 Golang,具体的网络协议可任意定制 • 在 Erlang 中,Erlang Message & Selective receive 是一等公民,Socket/File IO 基于其实现。
CERL - SDL 文法 vs. Go • 类型定义 • SDL: type AliasType = RealType • Go: type AliasType RealType • SDL 支持条件类型 • 一种任何语言中都没有的类型 • 函数定义 • SDL • [id=1] get(KeyT key) -> {ok, ValueT value} | false; • Go • func Get(key KeyT) (ok bool, value ValueT) • 更多关于 SDL 的资料 • http://ecug.org/sdl
CERL 2.0 • CERL 2.0 是雏形版的 Golang
Golang • 类型系统 (type system) • 内存管理 (memory management) • 接口 (interface) • 错误处理 (error processing) • 进程 (process)
类型系统 (type system) • C++ • 理念:只要愿意,我们可以自己做一个interface与内置类型一样的User Type。 • Java • 理念:User Type 都是 Object 类型。你需要注意这个世界有 2 套完全不同的类型体系。 • Golang • 理念:除了我们不推荐操作符重载外,User Type 与内置类型没有任何区别。
类型系统 (type system) - C++ class Int { private: int m_nVal; public: Int& assign(const Int& r) { this->m_nVal = r.m_nVal; return *this; } } 翻译成 C: struct Int { int m_nVal }; Int* Int_assign(Int* this, const Int* r) { this->m_nVal = r->m_nVal; return this; }
类型系统 (type system) - Go type Int int func (this *Int) assign(r Int) *Int { *this = r return this } 翻译成 C: typedef int Int; Int* Int_assign(Int* this, Int r) { *this = r; return this; }
类型系统 (type system) • 没有隐式的类型转换 (auto typecast) • 没有重载 (overload) • 没有继承,只有组合 • 用“匿名组合”可以部分达到继承的效果。 • 没有虚函数(virtual function) • 自然也就没有 override
类型组合的样例 type Foo {} func (r Foo) foo() { ... } type Bar {} func (r *Bar) bar() { ... } type Other {} func (r *Other) dosth() { ... } type Example { Foo *Bar other Other } var o Example o.foo() o.bar() o.other.dosth()
内存管理 (memory management) • C++ • 栈:局部变量 • 堆:new/delete, malloc/free • Java • 栈:局部变量 • 堆:new / GC • Go • 透明:语言自动选择何时使用栈,何时使用堆 • GC
内存管理 - C++ void f1() { Foo* foo = new Foo; ... } void f2() { Foo foo; ... } 注:f1 中的 foo 分配在堆上,f2 中的 foo 分配在栈上。
内存管理 - Golang func f1() { foo := &Foo{} } func f2() { foo := Foo{} } • 注:没有任何证据可以用来证明,f1 的 foo 分配在堆上,f2 的 foo 分配在栈上。
接口 (interface) • C++, Java, etc • 侵入式接口 • Golang • 非侵入性接口
接口 (interface) - 侵入式 interface Reader { int Read(void* buf, int n); } interface Reader2 { int Read(void* buf, int n); } class File : public Reader { int Read(void* buf, int n) { ... } } • File 满足接口 Reader,但不满足 Reader2,尽管两者实际上是一样的。File 需要知道它准备实现哪个接口。
接口 (interface) - 非侵入式 interface Reader { Read(buf []byte) (n int, err os.Error) } interface Reader2 { Read(buf []byte) (n int, err os.Error) } type File struct { ... } func (r *File) Read(buf []byte) (n int, err os.Error) { ... } • File 满足接口 Reader,也满足 Reader2。File 的实现并不需要知道接口 Reader 或者 Reader2。
非侵入式接口 • 好处 • 代码解耦。 • 在 Go 里面 interface 是按需定义,无需事先进行 “统筹”。
非侵入式接口:内部实现 • 有人感兴趣么?
错误处理 (error processing) • C++ • try .. catch • 句柄类/智能指针 (利用析构行为) • Java • try .. catch/finally • Go • defer
错误处理 - C++/Java FILE* fp = NULL; try { fp = fopen(...) if (fp == NULL) return; ... } finally { if (fp != NULL) { fclose(fp); } }
错误处理 - Go f, err := os.Open(...) if err != nil { return } defer f.Close() ...
进程 (process) • C++ • 进程:Thread / Fiber • 进程通信:没有标准的 Message Queue • Golang • 进程:goroutine • 进程通信:channel
进程 (process) - C++ class Worker { Worker(int a, string b, MQ* mq) { ... } void run() { ... this->m_mq.Push(result); } } static void ThreadProc(void* param) { Worker* worker = (Worker*)param; worker->run(); delete worker; } void caller() { MQ* mq = new MQ; CreateThread(ThreadProc, new Worker(1, "hello", mq)); result = mq.Pop(); delete mq; }
进程 (process) - Go func worker(a int, b string, mq chan ResultType) { ... mq <- result } func caller() { mq := make(chan ResultType) go worker(1, "hello", mq) result := <-mq }
Golang 的风险与建议 • 历史积累 • 如果团队已经有较多的代码积累,不建议换 Go 来重写一遍。 • 新模块可尝试 Go,但是需要考虑跨语言调用带来的额外负担。 • 开发 Windows 桌面、手机应用 • Go 语言目前主要面向服务端开发,不推荐应用于客户端开发领域。 • Golang 仍然在快速迭代变化 • 尽管已经可用,但 Golang 仍然在快速演变,语言细节可能变更,特别是库可能承受较大的演变。 • 团队需要预见此风险并进行风险防范。 • Golang 的社区仍然小众 • 人员招聘和培训成本较其他语言高。
QBox (Q 盘) • https://qbox.me/ • 专注于云存储领域的存储服务提供商 • 服务端 99% 代码基于 Golang • 累计约 10w 行 Golang 代码
Q & A xushiwei@qbox.net