Golang 很出色,为何它比 Scala/JVM 更胜一筹?

简介:

我是在几个月前学习Golang的,这要感谢@normanmaurer和@MegOnWheels的提议!倒不是因为我想要抹黑Scala和JVM,而是由于它们在将近十年后开始显得很糟糕。

为什么JVM开始显得很糟糕?

我当初开始使用JVM时,对于应用程序及其虚拟机/运行时环境彼此分开来感到很高兴。在几乎专职编写了9年的Scala代码后,我对它逐渐厌恶起来。原因何在?

因为JVM方面的差异让我开发出易于预测(言外之意:稳定)的应用程序极其困难。一个版本这么做,下一个版本搞坏了它,所以从一位优秀程序员的角度来看,你不得不另想办法,避开运行时环境方面的问题和功能。

其次,为了使用最新的功能特性,比如TLS服务器名称指示(SNI)――TLS1.3问世之后,该特性其实不是最先进的,你就要确保JVM/运行时环境是最新版本,无论想在哪里使用该特性,就得如此(TLSSNI是Java7->8)。

如果你是根本不用肩负运行职责的程序员,这可能对你来说是可以接受的,但是我不得不关注自己编写的代码的运行,就跟我不得不关注代码本身那样!

那么什么让golang在我看来如此出色?

你得到了静态链接的二进制文件。没有运行时环境,根本不用安装任何东西。

从部署的角度来看这尤为出色,因为你只要操心你的二进制文件及其资产(要是有的话)。

另外值得一提的是,由于我的Scala/Java.jar包(捆绑了所有依赖项)很少小于60MB,加上不小于500MB的JVM,这样一来浪费了大量的磁盘空间,许多方面需要定期更新。我的golang二进制文件却总共很少超过13MB。

最后但并非最不重要的一点是,scala-sbt这个构建工具糟糕透顶。真是这样。在我看来,它是人类有史以来所想出的一款最糟糕的构建工具!经常破坏向后兼容性,需要我处理新插件,真是糟透了!

我想要一款专门构建代码,并生成一种有用的二进制文件格式的构建工具。

这是“可靠”的工具实际上要做的事情。除了超级丰富的功能(比如测试、模糊以及所有这种优秀特性)外,它还要可靠地构建代码,又不需要我精心维护配置文件!到目前为止,简单的Makefile文件足以满足我的所有要求。

另外,我之前在Scala/JVM上需要Disk-Space时,rm-rf ~/.ivy2基本上解决了这个问题,因为你从sbt获取的所有依赖项jar包都驻留在此。但是一旦你这么做,你可能会另谋职业,因为一些工件/jar包可能不复存在,因而破坏你构建的代码。与之相反,在Golang中,我只要使用gitclone命令把依赖项源代码克隆到我的代码库,将它作为子模块添加到git,或者直接使用git,添加依赖项代码即可。

Scala二进制不兼容性(对原始文章的后续更新)

许多人指出,拥有二进制依赖项缓存几乎就跟拥有源代码一样好。

有没有遇到过多个Scala版本的情况?或者在Scala这个领域待的时间太短,不知道Scala二进制不兼容性?如果你喜欢这种东西,它们确实很出色。但是我不喜欢。我不想查出某某软件包这样的所有依赖项:它们只能在Scala2.9上运行,但需要为你的2.10项目、2.11或其他版本的项目重新编译。

inline错误修复(同样在原始文章发表后补充上去)

我不知道你们是怎么一个情况,反正我喜欢修复我使用的别人代码中的错误。

看到别人得益于我的代码,这让我有满满的自豪感,也让我感到很高兴。

所以,只要我不得不查明Scala/JVM方面的问题,我通常采取的程序就是下载该库源代码。然后试图让那个开发人员所用的构建工具运行起来。有时候这个工具是sbt,有时候是ant,有时候是maven,有时候是我听都没听说过的某个工具。听起来很好吗?

现在,我要花时间让这个工具运行起来,然后才能花时间来实际修复代码。

浪费时间啊!

如果你已经有源代码,如果我已经为目前的版本对它们进行了编译,如果你只要找到某一行代码,改动它,然后测试代码,岂不是要容易得多?

还是说,你宁可经历那个维护人员的构建工具的整个构建过程,把因而获得的.jar包放到你的缓存中,或者部署它,然后可能再次下载它,不得不改动构建的代码以便使用这个新的工件?

从简单的逻辑角度来看,我总是会选择第一个,因为它让我避免了许多头痛的问题,让我得以专注于手头的问题。

交叉编译

诚然,JVM上的这个问题还没有到你为自己的平台搞一个切实可行的Java运行时环境(JRE)的地步。在我看来,让无比庞大的JVM在你的RaspberryPI上运行也许不是使用其CPU的最佳方法。

那么,go如何处理这个问题呢?罗布·派克(RobPike)有一场精彩的演讲,介绍了go编译器的内部原理,为我们作了清楚的解释。自go1.7以来,你再也没有必要使用C这种语言了,而是可以让golang径直由Go编译成ASM。太棒了!

所以,为了在OSX上为我的RaspberryPI交叉编译一些纯粹的go代码,我只要运行:

GOOS=freebsd GOARCH=arm GOARM=6 go build src/*.go
就是这样。用scp命令传输该二进制文件,结果令人满意。何不在ARM本身上面这么做呢?a)在我的英特尔i7八核处理器上所花的时间长得多,b)ARM上的golang最新只能适用于版本1.4,因为新版本会有一些问题,但是使用1.8-HEAD交叉编译完全很好。

性能

从我头几个月在生产环境下使用golang的情况来看,我可以证实,就本人的使用场合(主要是网络节点)而言,golang速度极快,尽管零拷贝机制(Zero-Copy)在FreeBSD上还未得到支持。

对我的应用程序而言,内存耗用只是原来JVM项目的大概十分之一,因而在我们的数据中心操作过程中降低了对内存的要求,因而之前使用的JVM内存中大约十分之六从我们的FreeBSD虚拟机中释放出来,因而为我们新的客户机/应用程序腾出了大量资源。

结束语

Golang会成为我新的主要语言,Scala只是偶尔用一下,用于需要之前由我开发的软件得到支持的现有客户机。

文章转载自 开源中国社区 [http://www.oschina.net]

目录
相关文章
|
分布式计算 Java 编译器
关于jvm范型和scala implicit隐式参数以及classTag[T] typeTag[T]的一点思考
关于jvm范型和scala implicit隐式参数以及classTag[T] typeTag[T]的一点思考
134 0
|
SQL 存储 NoSQL
JVM 上数据处理语言的竞争:Kotlin, Scala 和 SPL
基于JVM的开源数据处理语言主要有Kotlin、Scala、SPL,下面对三者进行多方面的横向比较,从中找出开发效率最高的数据处理语言。本文的适用场景设定为项目开发中常见的数据处理和业务逻辑,以结构化数据为主,大数据和高性能不作为重点,也不涉及消息流、科学计算等特殊场景。......
226 0
JVM 上数据处理语言的竞争:Kotlin, Scala 和 SPL
|
SQL Java 数据处理
JVM 上数据处理语言的竞争:Kotlin, Scala 和 SPL
JVM 上数据处理语言的竞争:Kotlin, Scala 和 SPL
241 0
|
Java Scala Kotlin
JVM语言生态结构原理图 从Java,Kotlin,Scala,Groovy等语言的编译、执行全过程图示解析
JVM语言生态结构原理图 从Java,Kotlin,Scala,Groovy等语言的编译、执行全过程图示解析 JVM语言生态 by 陈光剑.png
1089 0
|
缓存 前端开发 安全
|
25天前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
208 1
|
2月前
|
存储 安全 Java
jvm 锁的 膨胀过程?锁内存怎么变化的
【10月更文挑战第3天】在Java虚拟机(JVM)中,`synchronized`关键字用于实现同步,确保多个线程在访问共享资源时的一致性和线程安全。JVM对`synchronized`进行了优化,以适应不同的竞争场景,这种优化主要体现在锁的膨胀过程,即从偏向锁到轻量级锁,再到重量级锁的转变。下面我们将详细介绍这一过程以及锁在内存中的变化。
40 4
|
15天前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。