由于 云巴 系统对高并发、低延迟的需求,咱们对各个语言、平台作了不少的调研比较工做。这天然就包括致力于开发高并发应用的 Go 和 Erlang。正则表达式
Go 对高并发的支持经过 goroutine 实现。goroutine 能够理解为轻量级的 线程(thread)。同一个 Go 应用建立的 goroutine 共享地址空间。shell
Erlang 的高并发经过轻量级 进程(process)实现,每个进程都有独立的状态记录。后端
另外,使用 goroutine 要注意,goroutine 运行完毕后,占用的内存放回内存池备用,不会释放。服务器
对于每个任务都须要有独立状态的场景,Erlang 的 process 更有优点。并发
Erlang 的任务调度器有一个 reduction budget 的概念。进程的任何操做都会形成预算消耗,包括 函数调用、调用 BIF、进程堆垃圾回收、ETS 读写、发消息(目标邮箱堆积的消息越多,消耗越大)。Erlang 的 正则表达式库 也被作了修改以支持 reductions。因此若是进程在长时间执行正则表达式匹配,也同样会消耗 reductions,也会被抢占。app
Go 以前的调度器只在 syscall 发生时调度,优化后能够在任何函数调用时调度。可是要注意,若是在 goroutine 里写一个死循环,Go 的调度器不能有效抢占,同一个调度器的 其余 goroutine 会被挂起。框架
像 Java 同样,Go 的垃圾回收是全局的,这意味着一旦垃圾回收被触发,全部的 goroutine 都会被暂停,形成一段时间的业务延迟。函数
Erlang 的垃圾回收是 进程 级别的,每个进程都有本身独立的垃圾回收器,一个进程的垃圾回收被触发,不会形成其余进程被挂起。相对来讲带来的业务延迟小。高并发
Erlang 的每个进程都有 进程 ID (PID),同时也能够给进程注册名字,也就是说每个进程都有独立的身份,能够有效的监控每个进程的状态。进程异常退出时,能够捕捉到退出事件,并重启进程(参见 otp 的 supervisor/worker)。单元测试
Go 的 goroutine 没有身份识别,goroutine 的状态没办法监控。
Erlang 动态语言的特色,使它自然支持 REPL,另外 Erlang 支持 remote shell,咱们能够在 Erlang 运行时,链接到 remote shell 与任何一个进程交互。这些特性对一个须要长期运行的复杂系统的维护带来了极大的便利。开发阶段也能有一些便利。
Go 是静态语言,不支持 REPL。
Erlang 是动态语言,有全部动态语言的全部缺点:
- 运行速度慢
- 不能作早期错误检查,须要依赖全覆盖单元测试
- 代码规模大了,给编写带来困扰
Erlang 如今也引入了 spec,对函数的参数返回值在编译时作类型检查,可是跟静态语言比起来效果差的很远。
不过正是由于是动态语言,Erlang 实现了运行时代码替换,这个特性对一个须要长时间运行的工业级产品,是一个很是重要的功能。
Go 是静态语言,运行速度快,编译时作严格的类型检查,能够避免不少隐患。
Erlang 的 OTP 框架支持服务器端开发常见的几种模式(applications, supervisors, wokers),方便代码的组织。
Go 暂时没看到相似的框架。
Go 是一个相对比较新的语言,虽然说如今不少项目都开始支持 Go,但不少第三方库的成熟度暂时不如 Erlang。
对于要求低延迟、高并发的后端服务,咱们近期仍是采用 Erlang 为主。但使用 Erlang 的过程当中,Erlang 缺少静态检查的手段,也是一个很麻烦的问题,目前的作法是要求你们都使用 IntelliJ IDEA 编写代码,能够经过 IDE 提早发现部分语言问题。
同时咱们会持续关注 Go 的发展。
关于做者:
weibo: @Tiger_张虎, 云巴 (yunba.io) 创始人,yunba.io 云后端服务。 JPush 创始人,原CTO。 Oracle VM 创始团队成员。
原文:http://zhang.hu/go-vs-erlang/