2019独角兽企业重金招聘Python工程师标准>>>
我不知道有什么办法说服人放弃一种语言,用另一种。不是因为我们没法客观比较,而是一般人们会因为各种原因拒绝客观比较。
我在腾讯工作的时候,我们团队和深圳一个团队合并。我注意到深圳一位同事用Scala,写的程序相对用Java简练清晰,让人眼前一亮。我因此专门学习了一段时间Scala。于此同时,我也在学习Go。两个学习过程同时开始,没有什么偏见。但是后来开始开发Peacock(http://arxiv.org/abs/1405.4402)的时候我决定用Go,而不是Scala。原因有二:
- JVM程序dockerization的成本太高了:每个docker container里得安装JVM和标准库,花掉几百MB。一台机器如果跑100个container,一个机群100台机器,一个月要为此给Google Compute Engine或者Amazon AWS多付多少钱?程序员可以不算账,老板可不行。我在“在未来,Go语言能否撼动Java在Android、Hadoop大数据、云计算领域的地位? - 王益的回答”里也提到这个问题。不用container技术可以吗?这可以做另外一个问题讨论了。只提醒一点:Docker用的Linux kernel cgroup系统调用是2007年Google Borg的开发者贡献给Linus的,而Google Borg是Google MapReduce框架的代码量只有Hadoop的百分之一,而功能却强大得多的根本原因。更详细的讨论请见这里:分布式机器学习的故事:Docker改变世界 - Occam's Razor - 知乎专栏。
- Scala的并发语法(和其他很多想法)直接借鉴于functional programming languages学术研究成果,不够贴近工程需要。12年前,我的同学王垠教了我DrScheme(现在叫做Racket了)。这是MIT开发的计算机系本科生的启蒙语言。其中有一种语法叫future,也就是Scala里支持并发的语法。Future是1972年就写进书里了《google.com 的页面》的。它要求一个并发单元最后会返回,并且要返回一个值。这个要求很符合pure functional programming(程序里除了IO不允许有side effect)的调调,但是不符合实际工程工作需要——我要起一个并发单元执行一个Web server,这事儿显然就没有什么返回值。Go的goroutine显然更务实——不需要返回什么值。那结果怎么传回来呢?用channel啊。实际上,goroutine + channel可以完全复现future语法:只需要把一个future定义为一个返回channel的goroutine即可——代码行数都和Scala一样。请看这里的例子:http://www.golangpatterns.info/concurrency/futures。
Peacock现在已经在腾讯广告系统和其他产品里应用。它的训练系统运行在数百台机器上,一个任务里的并发单元以百万计。很多大规模并行机器学习系统的并发规模都如此甚至更大,包括Google Machine Translation背后的language model training system,以及广告点击率预估系统(请参见:Research Blog: Lessons learned developing a practical large scale machine learning system)。在这样的架构下,上述两个因素就成了决定性因素了。
回到主题。我不确定Scala任何时候都比Go好用,但是上述实践让我基本明白,大规模并行系统的开发还是用Go比较现实。虽然我看到很多朋友说JVM语言的“生态好”,但是恐怕这很快就会随着Docker、etcd、CoreOS和Kubernetes引导开源社区而变成过去式了,所以我不敢把“生态好”当做一个重要因素来验证Scala更适合开发大规模并发系统。