Stream 公司最近将其核心服务的后端从 Python 切换成了 Go, 虽然他们内部还在使用 Python, 但是公司已经决定从现在开始在 Go 中编写所有性能密集型代码本文, Stream 首席执行官和创始人 Thierry Schellenbach 解释了公司的这一决定
选择项目或产品的编程语言会受到许多因素驱动, 与所有技术决策一样, 没有完美的答案足以解决所有问题 Stream 之所以这么做, 是因为感受到了 Go 语言的巨大好处
这与 Stream 的产品有关 Stream 是用于构建, 缩放个性化新闻源和活动流的 API 每月为 3 亿多用户提供约 10 亿次 API 请求因此, 性能和可靠性是 Stream 制定每项技术决策的最重要原因
Python 和 GO: 性能对比!
Go 最大的卖点可能就是性能, 无论是运行时间还是编译时间它在大多数计算基准测试中与 Java 或 C ++ 相当在 Stream 的实际使用中, GO 比 Python 快大约 30 倍
选择性能优秀的工具非常重要 (Stream 已经优化了 Cassandra,PostgreSQL,Redis 和许多其他技术) 然而, 有时发现系统中的瓶颈确实是 Python 引起的, 像序列化, 排序和聚合等计算繁重的任务有时会比从网络数据存储检索数据花费更长的时间
Go 编译器 (本身是用 Go 编写的) 也非常快使用 Go 编写的 Stream 中最复杂的微服务只需要 6 秒即可编译完成, 与 Java 和 C ++ 等工具链相比, 这是一个重大胜利
此外, 阅读 Go 语言代码往往非常简单, GO 干净的风格让读取和推理更容易
本地并发
通过 goroutines 和 channel 将并发性融入到语言中 Goroutines 在概念上类似于操作系统线程, 但非常便宜每个成本只有几 KB 的堆栈空间 Go 运行时可以处理智能多路复用 goroutines, 这一切对程序员来说是透明的单个程序拥有数千个 goroutines 并不罕见例如, net / http 软件包中的服务器为每个传入的 HTTP 请求创建一个 goroutine
在真正的 Go 语言中, goroutine 非常简单: 只需在 go 关键字前添加一个函数调用, 让它运行在自己的 goroutine 中即可
Go 世界的传统观点是不通过共享内存来交流, 相反的是, 通过通信来共享内存在 goroutines 之间进行通信的原语是 channel, 它们与 goroutines 一样易于使用 channel 有一个类型, 可以通过直观的箭头语法轻松地在 goroutine 之间传递数据虽然简单, 但 channel 非常强大通过预先考虑, 与传统系统相比, 制作大规模并发系统是一件轻而易举的事情
使用简单的并发工具, 可以解决那些经常导致错误的复杂问题 Go 随附内置竞速检测器, 可以更轻松检测异步代码中的竞争状态
生态系统
Go 仍然是编译语言环境的新手, 远比不上 C ++ 和 Java 等传统语言的普及程度虽然只有大约 5% 的程序员知道 Go, 但是这个数字还在不断增长, 而且这种增长是由于语言的易用性所致虽然语言快速且功能强大, 但该语言只有 25 个保留字(与 C ++ 92 或 Java 53 相比), 对于大多数开发人员来说, 它只会引入很少的新概念
建立一个 Go 开发团队比大多数语言更容易, 因为它更容易学习
随 Go 提供的内置库在开箱即用, 功能强大使用 `net / http` 包制作 HTTP 服务只需要几行代码, 并且本地支持 http / 2,TLS 和 websocket 等社区软件包的生态系统也很出色, 适用于 Redis,RabbitMQ,PostgreSQL 和 RocksDB 等
其他福利
Go 节省时间的另一种方式是使用 Gofmt 它是一个命令行工具, 可与大多数编辑器集成并自动将代码格式化为事实标准如果格式不正确, 代码仍会编译, 但除非通过 gofmt 运行代码以保持整个代码库格式一致, 否则将不会查看 pull 请求这使代码审查人员能够专注于代码而不是花时间挑剔格式
Go 有助于开发微服务架构, gRPC 和 Google 的协议缓冲区是管理微服务之间通信的好方法, Go 有一流的支持
Python 与 Go
Stream 服务中的一个强大功能是排名提要排名提要允许用户为提要指定一个评分函数, 以便控制提取时的排序方式评分算法可以提供很多变量来确定排名, 但基于流行度的一个很好的例子可能是这样的:
要支持这种排名方法, Python 和 Go 代码都需要: 解析分数的表达式在这种情况下, 我们想将字符串 simple_gauss(time)* popular 变成一个函数, 它将一个活动作为输入并返回一个分数作为输出
根据 JSON 配置创建部分函数例如, 我们希望 simple_gauss 以五天的刻度, 一天的偏移量和 0.3 的衰减因子来调用 decay_gauss
如果在活动中没有定义某个字段, 则应对默认值配置进行压缩, 以便进行回退
使用步骤 1 中的功能对 Feed 中的所有活动进行评分
开发 Python 版本的示例花了大约三天的时间编写代码, 单元测试和文档接下来, 团队花了大约两周的时间来优化代码其中一项优化是将分数表达式 (simple_gauss(time)* popular) 转换为抽象语法树该团队还实施了高速缓存逻辑, 预先计算了将来某些时间的分数
相比之下, 开发此代码的 Go 版本需要大约四天的时间, 并且性能不需要任何进一步的优化虽然 Python 的开发初期看来更快, 但 Go 版本最终需要的工作量大大减少
在优化代码库时节省的时间归功于 Go 语言的特点使用 Python, 程序员不得不将表达式解析为抽象语法树, 并优化 / 剖析通过排名公开的每个函数
结论
Go 是编写微服务的伟大语言它的速度非常快, 具有原生并发原语, 对现有工具的卓越支持, 并且开发起来非常有趣与 Ruby 或 Python 等脚本语言相比, Go 语言可能需要更长的时间, 但维护成本要低得多, 而且将节省大量时间优化代码
重要的是, Stream 仍然在使用 Python, 它是有意义的例如, 仪表板, 网站和个性化订阅源的机器学习使用 Python, 因为工具更好 Stream 不会马上告别 Python, 但是今后会在 Go 中编写所有性能密集型代码
来源: http://developer.51cto.com/art/201803/569193.htm