点击上方“ csdn ”,选择“置顶公众号”
关键时刻,第一时间送达!
你知道我们一共有多少种编程语言吗?
根据维基百科数据统计(
原因 5:快速的编译时间
当前我们使用 go 编写的最大微服务的编译时间只需 6 秒。相较于 java 和 c++呆滞的编译速度,go 的快速编译时间是一个主要的效率优势。我热爱击剑,但是当我依然记得代码应该做什么之时,事情已经完成就更好了。
go 之前的代码编译
原因 6:打造团队的能力
首先,最明显的一点是:go 的开发者远没有 c++和 java 等旧语言多。据知,有 38% 的开发者了解 java,19.3% 的开发者了解 c++,只有 4.6% 的开发者知道 go。github 数据表明了相似的趋势:相较于 erlang、scala 和 elixir,go 更为流行,但是相较于 java 和 c++ 就不是了。
幸运的是 go 非常简单,且易于学习。它只提供了基本功能而没有多余。go 引入的新概念是「defer」声明,以及内置的带有 goroutines 和通道的并发性管理。正是由于 go 的简单性,任何的 python、elixir、c++、scala 或者 java 开发者皆可在一月内组建成一个高效的 go 团队。
原因 7:强大的生态系统
对我们这么大小的团队(大约 20 人)而言,生态系统很重要。如果你需要重做每块功能,那就无法为客户创造收益了。go 有着强大的工具支持,面向 redis、rabbitmq、postgresql、template parsing、task scheduling、expression parsing 和 rocksdb 的稳定的库。
go 的生态系统相比于 rust、elixir 这样的语言有很大的优势。当然,它又略逊于 java、python 或 node 这样的语言,但它很稳定,而且你会发现在很多基础需求上,已经有高质量的文件包可用了。
原因 8:gofmt,强制代码格式
gofmt 是一种强大的命令行功能,内建在 go 的编译器中来规定代码的格式。从功能上看,它类似于 python 的 autopep8。格式一致很重要,但实际的格式标准并不总是非常重要。gofmt 用一种官方的形式规格代码,避免了不必要的讨论。
原因 9:grpc 和 protocol buffers
go 语言对 protocol buffers 和 grpc 有一流的支持。这两个工具能一起友好地工作以构建需要通过 rpc 进行通信的微服务器(microservices)。我们只需要写一个清单(manifest)就能定义 rpc 调用发生的情况和参数,然后从该清单将自动生成服务器和客户端代码。这样产生代码不仅快速,同时网络占用也非常少。
从相同的清单,我们可以从不同的语言生成客户端代码,例如 c++、java、python 和 ruby。因此内部通信的 reset 端点不会产生分歧,我们每次也就需要编写几乎相同的客户端和服务器代码。
使用 go 语言的缺点
缺点 1:缺少框架
go 语言没有一个主要的框架,如 ruby 的 rails 框架、python 的 django 框架或 php 的 laravel。这是 go 语言社区激烈讨论的问题,因为许多人认为我们不应该从使用框架开始。在很多案例情况中确实如此,但如果只是希望构建一个简单的 crud api,那么使用 django/djrf、rails laravel 或 phoenix 将简单地多。
缺点 2:错误处理
go 语言通过函数和预期的调用代码简单地返回错误(或返回调用堆栈)而帮助开发者处理编译报错。虽然这种方法是有效的,但很容易丢失错误发生的范围,因此我们也很难向用户提供有意义的错误信息。错误包(errors package)可以允许我们添加返回错误的上下文和堆栈追踪而解决该问题。
另一个问题是我们可能会忘记处理报错。诸如 errcheck 和 megacheck 等静态分析工具可以避免出现这些失误。虽然这些解决方案十分有效,但可能并不是那么正确的方法。
缺点 3:软件包管理
go 语言的软件包管理绝对不是完美的。默认情况下,它没有办法制定特定版本的依赖库,也无法创建可复写的 builds。相比之下 python、node 和 ruby 都有更好的软件包管理系统。然而通过正确的工具,go 语言的软件包管理也可以表现得不错。
我们可以使用 dep 来管理依赖项,它也能指定特定的软件包版本。除此之外,我们还可以使用一个名为 virtualgo 的开源工具,它能轻松地管理 go 语言编写的多个项目。
python vs go
我们实施的一个有趣实验是用 python 写排名 feed,然后用 go 改写。看下面这种排序方法的示例:
{
functions: {
simple_gauss: {
base: decay_gauss,
scale: 5d,
offset: 1d,
decay: 0.3
},
popularity_gauss: {
scale: 100,
offset: 5,
decay: 0.5
defaults: {
popularity: 1
score: simple_gauss(time)*popularity
python 和 go 代码都需要以下要求从而支持上面的排序方法:
解析得分的表达。在此示例中,我们想要把 simple_gauss(time)*popularity 字符串转变为一种函数,能够把 activity 作为输入然后给出得分作为输出。
在 json config 上创建部分函数。例如,我们想要「simple_gauss」调用「decay_gauss」,且带有的键值对为scale: 5d、offset: 1d、decay: 0.3。
解析「defaults」配置,便于某个领域没有明确定义的情况下有所反馈。
从 step1 开始使用函数,为 feed 中的所有 activity 打分。
开发 python 版本排序代码大约需要 3 天,包括写代码、测试和建立文档。接下来,我么花费大约 2 周的时间优化代码。其中一个优化是把得分表达 simple_gauss(time)*popularity 转译进一个抽象语法树。我们也实现了 caching logic,之后会预先计算每次的得分。
相比之下,开发 go 版本的代码需要 4 天,但之后不需要更多的优化。所以虽然最初的开发上 python 更快,但 go 最终需要的工作量更少。此外,go 代码要比高度优化的 python 代码快了 40 多倍。
以上只是我们转向 go 所体验到的一种好处。当然,也不能这么做比较:
该排序代码是我用 go 写的第一个项目;
go 代码是在 python 代码之后写的,所以提前理解了该案例;
go 的表达解析库质量优越。
elixir vs go
我们评估的另一种语言是 elixir。elixir 建立在 erlang 虚拟机上。这是一种迷人的语言,我们之所以想到它是因为我们组员中有一个在 erlang 上非常有经验。
在使用案例中,我们观察到 go 的原始性能更好。go 和 elixir 都能很好地处理数千条并行需求,然而,如果是单独的要求,go 实际上更快。相对于 elixir,我们选择 go 的另一个原因是生态系统。在我们需求的组件上,go 的库更为成熟。在很多案例中,elixir 库不适合产品使用。同时,也很难找到/训练同样使用 elixir 的开发者。
结论
go 是一种非常高效的语言,高度支持并发性。同时,它也像 c++和 java 一样快。虽然相比于 python 和 ruby,使用 go 建立东西需要更多的时间,但在后续的代码优化上可以节省大量时间。在 stream,我们有个小型开发团队为 2 亿终端用户提供 feed 流。对新手开发者而言,go 结合了强大的生态系统、易于上手,也有超快的表现、高度支持并发性,富有成效的编程环境使它成为了一种好的选择。stream 仍旧使用 python 做个性化 feed,但所有性能密集型的代码将会用 go 来编写。
-------- 热闻回顾 --------
一个 38 岁程序员的中年危机
wi-fi 爆重大安全漏洞,android、ios、windows 等所有无线设备都不安全了
从程序员之死看 it 人士如何摆脱低情商诅咒