近日,Python 被纳入全国计算机等级考试科目、编入了小学教材、获得了 2018 年顶级编程语言荣誉,可以说,Python 要多火就有多火。而本文并非为此火上添油,而是适时地为 Python 浇了一盆凉水,稳步发展才是一门编程语言的正轨。本文作者使用了 Go 语言完成了曾经用 Python 搞定的多种任务,对比发现,Go 语言的方法似乎更胜一筹。
其中,完成的任务比如说:
处理 S3 上存储的 Cloudfront 日志;
在 S3 中将 TB 级别的数据从一个桶移到另一个桶,或者其他区域;
比较数据库中的数据和 S3 中的文件,确保数据的同步。
许多都是一次性的任务,因此脚本语言很合适。程序要能很快写出来,而且基本上用完就不会再用了。通常每次任务都是全新并且唯一的,因此几乎没有代码重用的可能。
下面是 Go 比 Python 强的地方:
编译器很好
我在 Python 中一直犯愚蠢的错误。比如搞错变量名或函数名,或者给函数传递错误的参数。Devtools 能发现一些错误,但通常这些工具需要特别设置。我从来没能完美设置好 pylint,我也不喜欢那些需要单独配置的笨重的 IDE。
最糟糕的情况是隐藏在条件逻辑后面的错误变量名。代码会运行几个小时,直到错误触发。然后就不得不一切从头开始。
单元测试通常能捕获这些错误,但很难获得 100% 的代码覆盖率,而且对于一次性的脚本我也不想浪费时间写测试。
编译语言能完全避免这些问题。编译器能找出所有愚蠢的错误。因此,对于任何超过 100 行代码的任务,我更喜欢使用 Go。
开发速度
编译器的缺点就是通常会降低开发速度。尤其在 C/C++ 和 Java 上特别明显。
但 Go 非常简单,我发现它对开发速度的影响非常小。不要误会,我用 Python 依然更快,但用 Go 通常能达到 Python 的 85% 效率。
考虑到使用编译器能犯更少的错误,85% 已经非常值得了。
更好的并发性
你一定知道,Go 的开发目的就是并发执行。
在我的团队中我们一般都需要并发编程,因为我们要处理 S3 或数据库中的海量数据。
如果任务中有很多 IO(许多任务都是如此),那我们可以用 Python 的线程。但如果需要很多 CPU,那 Python 就很难办,因为它有全局解释器锁(Global Interpreter Lock)。
而使用 Go 的多线程,无需任何特殊处理就能正常工作,这一点非常棒。你一定体会过在 Python 中按 Ctrl-C 试图结束多线程任务却毫无反应的情况吧?
更容易部署
我喜欢单一的二进制文件。通常我在 EC2 机器上运行代码,使之在网络上更靠近与 S3 和数据库。使用 Python,我需要在远程机器上安装所有的包,并确保其他人没有安装任何冲突的东西。
虽然 Virtualenv 能解决这个问题,但我依然认为 Go 更容易。
通常我会在我的 Mac 上将代码交叉编译成 Linux 二进制文件,然后复制到远程机器上,然后就可以执行了。所有依赖都被放到二进制文件中了。
一致的风格
最初,gofmt 工具的确挺烦人,特别是他们使用 tab 而不是使用空格。我认为他们简直是疯了。
但用得多了后,我开始依赖它了。它能直接提供完美的代码格式。不管是哪个项目,所有代码都有同样的风格,因为风格就是标准 Go 工具链中的一部分。
而在 Python 中达到同样的效果需要更多的功夫。必须正确配置 pylint,并保证每个项目的配置都是一样的。
更好的工具链
gofmt 只是通用工具链的一个例子。所有我喜欢的编辑器,不论是 VSCode、vim 还是 SublimeText,都有非常好用的 Go 语言扩展,使用标准的 Go 工具链。
因此,我能获得近似 Java 的只能提示,但无需使用真正的 IDE。而使用 Python 就从来没能享受过这样的功能。
缺点
我读到的许多批评 Go 语言的文章都在说它缺乏某个明显的功能,比如泛型。但没有泛型我也从来没遇到过麻烦。实际上 map 和 slice 能完成许多工作。不过我却有些其他的问题。
Go 是有观点的语言
首先,Go 可能是我用过的最有观点(opinioned)的语言了。从强迫使用 Tab 而不是空格(假设你用 gofmt),到强迫使用固定的目录格式,甚至强迫在GOPATH 环境变量中写代码,许多 Go 的东西都没办法改变。
有观点的理由之一就是这样易于学习,因为这些特点都不会改变。但如果你不想导出的名字以大写字母开头,那就没办法了。不过幸运的是,这些问题都不会成为我不使用 Go 的理由,但我能理解有些人无法接受。
而 Python 则更灵活。
缺乏库支持
在这个领域比较 Python 和 Go 并不太公平。Go 非常年轻,但我还是会在发现 Go 本身不支持某个功能时感到很不解。更让我失望的是,一些人在 StackOverfolw 上贴了些本应是内置函数的代码,然后每个人都仿佛没事儿一样直接把代码粘贴到项目里使用。
举两个近几年我发现的例子:
对 slice 排序(幸运的是在 Go 1.8 中变得容易得多了)
math.round 只能用于整数,而不能四舍五入成浮点数(比如四舍五入到最近的.5)。甚至在 Go 1.10 之前都没有 math.round。
当然,一些原因是因为 Go 没有泛型,一些是因为 Go 的设计思想就是只把绝对必要的东西加到标准库中。
我理解这两个原因,不过在遇到非常简单的功能却不得不自己写代码时还是觉得很烦人。
希望 Go 语言能越来越好,痛点能越来越少。
原文:thinkfaster.co/2018/07/goo…译文:CSDN资讯作者:Jake Wilson译者:弯月,责编:屠敏
CSDN学院GO语言课程推荐:
2.Go语言-基础篇
3.Go语言-进阶篇