从Erlang 到CERL 到Golang

Download Report

Transcript 从Erlang 到CERL 到Golang

从 Erlang 到 CERL 到 Golang
许式伟
[email protected]
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
[email protected]