关于Go 和Erlang的一些想法
原文链接:http://blog.erlware.org/some-thoughts-on-go-and-erlang/
以下为本人翻译,仅用于交流学习,版权归原作者所有,转载请注明出处,请不要用于商业用途。
更新: 我发现我这篇文章没有把观点说明白。我并不是说Go不行或者应该改进,因为它跟Erlang是不一样的。我想说的是在可用性和低延迟不可缺少的高并发后端领域来说,Go仍然不能替代Erlang。 需要注意的是,我写这篇文章并不是要关于某一种语言比如Julia。我听说不仅仅在新项目里,还有在一些老项目要替换新语言里,Go慢慢成了Erlang的替代者。没有人说Julia也是这样,但是Go和Node.js却被一些人看作是Erlang的友好的替代者。Erlang并不是适合所有,这里我只明确讨论Erlang适合的地方和Go不适合的地方。
我打算去掉我的一些关于不喜爱Go的主观言论,比如语法或者或者缺少模式匹配,并且会解释这门语言的本身以及某些系统下它的运行时并不适合的客观原因。
Go的长处
客户端
正如Rob Pike曾经说过的,他最大的惊讶是Go吸引了很多Python和Ruby程序员转向它而不是C++。对我来说,这种趋势也很乐意看到。用pip或者gems安装的那些慢的客户端也不会再出现了 (尽管有一些用Node.js做客户端的越来越多的原因,卧槽那Keybase呢)。
GO为开发者提供了一种快速的,易于使用的带有垃圾收集和并发原语的高级静态类型语言。因为这些优点,C++开发者转向Go是容易的,在我机器上经常崩溃的程序Hipchat 和 Spotify,就是用C++写的,它就擅长不恰当的使用内存。不过Rob Pike指出C++开发者却不想使用这个简单而又强大的Go。而Ruby和Python程序员却愿意转向Go。
工具
不基于第三方工具,只基于第三方库,编译可执行过程能很容易完成,这是Go的长处。虽然这工具并不完美,但有一些工具能填补这些缺点,比如Godep,对于这门语言来说,是一个巨大的进步。
Go的缺点
在编写低延迟的容错系统中,一些Go的设计是有缺陷的。
并发
是的,在第一部分的附加部分,我提到了并发原语,正是这个原因,很多客户端下Go代替了Ruby,python或者C++。但是在需要容错的复杂的后端系统中,Go和其他语言一样在共享状态方面并不适合。
抢占调度
这方面Go就好多了。Go的抢占调度是通过系统调完成的,但是现在在每个函数调用中,一个goroutine检查栈的时候抢占调度也会发生。如果这个goroutine运行了很长时间,它有可能被标记为失败(引起抢占调度) 。尽管这是个改进,但是它仍然落后Erlang的计数减少和后来为了改进C而新加入其中的脏调度。
垃圾收集
Go中的垃圾收集是全局标记和清除式的。这会在清除阶段暂停所有goroutines,这对于低延迟来说是糟糕的。而且,低延迟很困难,运行时做得越多,对来你说越好。
错误处理
这里不是要讨论如果第二个返回值是nil的话没有异常或者异常检查的用法。Goroutine没有身份标识意味着Go缺少了连接和监控goroutines的能力。没有连接(被panic和defer代替)以及没有进程隔离意味着你在稳定状态下无法在崩溃的时候回退和重启。这样会导致产品里有很多bug,而且其中很多都是海森堡bug,所以能够使进程之间互相隔离但是要基于他们的依赖,是能容错的关键。
另外在错误处理上Go有nil,它在2014年被认为是可行的,但是我却不认同,不过我先不管这些,先看看再说。
反省
在开发的时候没有REPL是很烦的,而没有远程shell对于一个正在运行的系统而言却是一个致命伤。Erlang有一个令人印象深刻的tracing功能,以及基于这种功能的工具如recon trace。Erlang的自我内省极大的改善了开发,同时也改善了在复杂的系统上的维护。
静态连接
是的,一件事情本来是好的但是却变成了不好的,比如在一个系统上要花很多时间运行。虽然没有连接会导致执行变慢,但是在运行的系统上进行代码替换方面它却给了Erlang一个优点。很重要的一点,由于Erlang的调度和垃圾收集策略,各种速度的权衡并不意味着在同一个应用中Erlang会比其他语言慢,尤其是仅有Erlang在运行的情况下。
代码组织
OTP框架为通用模式提供了库。OTP不仅可以用更少更优的抽象代码去写程序而且能提高可读性。随着应用里加入了OTP标准,上级和普通员工(genserver,genfsm,gen_event)意味着一个新的开发人员通过进程树能够很快的胜任工作以及如何沟通交互。Go的channels,不可识别的goroutines以及缺少模式去分隔goroutines到不同的模块将导致代码越来越难写。
Go应该改变吗,能改变吗?
Erlang已经出现了数十年了,而Go还是个新孩子,那么Go能否在这些领域改进呢?也许有的可以,但是更多的是不可以,因为这门语言本身缺乏容错和低延迟。 这并不是说Go就是不好的或者错误的,跟其他类似Erlang语言相比,它能在不同的问题处理上做出不同的更合适的选择。