速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

Stream 从 Python 切换到 Go 的原因

  • 2018-07-21
  • 本文字数:3416 字

    阅读完需:约 11 分钟

Stream 最近将其后端核心服务从 Python 改成了 Go。虽然他们的某些模块仍然在使用 Python,但是公司已决定从现在开始使用 Go 来编写对性能要求较高的代码。文中,Stream 的 CEO 兼创始人 Thierry Schellenbach 将解释他们决定转向 Go 的原因。

影响项目或者产品编程语言选型的因素有很多。与任何技术决策一样,选择编程语言时同样需要多方面权衡,即使这样,最终的选择结果都很难是完美的。我们最近将后端的核心服务从 Python 改成了 Go,原因有很多,好处也很多。

为了理解这一变化的重要性,需要先了解我们的产品。Stream 是一套用于构建、伸缩、定制化新闻源和活动流的 API。每个月为 3 亿多用户提供约 10 亿次 API 请求。我们尤其关注性能和可靠性,这两点因素决定了我们制定的每项技术决策。

性能更优

Go 最大的卖点在于它的性能,无论在运行还是编译时它都有突出的性能优势。它与 Java 或者 C++ 的运算速度几乎相当。在实际使用中,我们发现它比 Python 大约快 30 倍。

选择快速工具对提升系统性能非常重要,因此我们对 Cassandra、PostgreSQL、Redis 以及其他一些技术进行了优化。然而,很多时候我们发现系统仍然存在瓶颈,而瓶颈正好在于我们的编程语言 Python。Python 在执行序列化、排序和聚合等计算密集型任务时需要花费很长的时间,有时比从网络上存取和检索数据花费的时间更长。我们知道这个时间是可以优化的。从 Python 切换到 Go 就可以缩短时间,这样一来,应用程序代码就更像是服务之间的粘合剂,而不再是优化中的主要瓶颈。

用 Go 编写的 Go 编译器也非常快。Stream 中最复杂的微服务就采用 Go 编写,它的编译时间仅仅需要 6 秒,Java 和 C++ 等工具链则慢得多,快则一分钟,慢则数小时。

名副其实的简单

简单是 Go 的重要特征!我敢向你保证,阅读 Go 语言的代码明显感觉更加简单。我们已经从多个 Python 代码库中迁移出来,我们发现这些 Python 代码的风格和框架会因为作者的不同而风格各异,往往带有很多作者个性化的东西。而 Go 恰恰相反,它推崇干净的代码风格,同时要求作者编写代码时严格遵守规范,禁止作者“自作聪明”。虽然这样有时候会使用更加冗长的代码,牺牲了代码的简洁性,但是却让代码更容易阅读和理解了。这样一来,Go 才得以加快开发人员阅读他人代码的速度,同时,阅读自己曾经编写的代码也更容易。

原生并发性

Go 在语言层面通过 goroutine 和 channel 支持了并发。此概念源自 Tony Hoare 的 CSP 模式,它让程序员处理并发变得不再困难。

goroutine 类似于操作系统的线程,但其运行消耗的系统资源更小,每个 goroutine 仅需几 KB 的堆栈空间。Go 运行时可以在操作系统线程之上处理多路 goroutine。虽然在后台执行,但它对于程序员来说是可见的。单个程序拥有数千个 goroutine 也并不罕见。比如,net/http 软件包中的服务器程序针对每个 HTTP 请求都会创建一个 goroutine。

在 Go 中启动 goroutine 非常简单,只需通过 go 关键字添加一个函数调用,即可启动一个 goroutine,并让该函数运行在自己的 goroutine 中。

Go 有一句重要的格言,即:不要通过共享内存来通信,相反,通过通信来共享内存 。Goroutine 之间通过 channel 进行通信,channel 的使用方法与 goroutine 一样简单。Channel 拥有类型,可以通过直观的箭头语法轻松实现 goroutine 之间的数据传递。尽管 channel 使用简单,但是其功能非常强大。在设计时只要预先稍作考虑,与传统的系统相比,使用 Go 便能够轻而易举地开发大规模并发系统。

使用简单的并发工具可以解决那些经常导致错误的问题。Go 内置了竞态条件检测器,可以更轻松地检测异步代码中的竞争状态。

语言生态

跟 C++ 和 Java 这样已经高度普及的传统语言相比,Go 仍然是编译语言领域的新手。虽然目前大约只有 5%的程序员知道 Go,但是得益于它的易用性,这个数字在不断增长。虽然 Go 语言速度快且功能强,但它只有 25 个保留字。相比于 C++ 的 92 个保留字,以及 Java 的 53 个保留字,Go 显得非常简洁。过多的保留字会增加程序员的学习成本。

由于 Go 上手非常容易,因此组建 Go 开发团队相比其他语言来说更容易。Go 初学者可以很快入门并精通该语言。这使得雇主甚至可以招聘其他背景的开发人员,然后加以短期培训即可使其成为合格的 Go 工程师。

Go 提供的内置库开箱即用且功能强大。使用“net/http”仅需几行代码即可实现 HTTP 服务器,并且还支持 http/2、TLS 和 websocket。Go 社区软件包的生态系统也很出色,已经出现了很多与 Redis、RabbitMQ、PostgreSQL、模板以及 RocksDB 相关的库,它们运行稳定且更新频繁。

其他优势

在前文中我提到了 Go 并不鼓励程序员“自作聪明”,它并没有提供可能会节省时间的功能,比如可嵌套的三元运算符。

Go 采用另一种方式来节省时间,它既没有选择制表符也没有选择空格,而是转而使用了 gofmt。它是一种命令行工具,可与大多数编辑器集成并自动将代码格式化为特定的格式。即使格式不正确代码仍会编译,但是拉取请求会被忽略,除非代码通过 gofmt 并且能够保持整个代码库格式一致。这使得代码评审人员能够专注在代码上,而不必在格式上浪费时间。

Go 有助于开发微服务。谷歌的 protobuf 和 gRPC 是微服务间通信的基础,Go 对它们提供了很好的支持。作为开发人员,我们只需在清单文件中定义一项服务,工具便会自动生成客户端和服务器端代码,并且保证代码的高性能以及很低的网络负载。此外,清单文件还可以被其他语言用来生成他们自己的客户端和服务器端代码。所以,如果我们决定用其他技术来替代部分架构,之后的任务会更加简单。

Python vs. Go

Stream 服务强大功能之一是 feed 排名。feed 排名允许我们的用户为 feed 指定一个评分函数,以便控制排序方式。评分算法可以提供很多变量来确定排名,其中基于流行度的一个例子可能是这样的:

复制代码
{
"functions":{
"simple_gauss":{
"base":"decay_gauss",
"scale":"5d",
"offset":"1d",
"decay":"0.3"
},
"popularity_gauss":{
"base":"decay_gauss",
"scale":"100",
"offset":"5",
"decay":"0.5"
}
},
"defaults": {
"popularity": 1
},
"score":"simple_gauss(time)*popularity"
}
  1. 为了支持这种排名方法,Python 和 Go 代码都需要解析表达式计算得分。在这种情况下,我们需要将字符串 “ simple_gauss(time)* popular ” 变成一个函数,它将活动数据作为输入,并输出分数。
  2. 基于 JSON 配置创建部分功能。例如,我们希望“simple_gauss”以五天的时间窗、一天的偏移量以及 0.3 的衰减因子来调用“decay_gauss”。
  3. 解析“默认”配置,以便在活动数据中发现未定义的字段时进行回退。
  4. 使用步骤 1 中的功能对 feed 中的所有活动数据进行评分。

开发 Python 版本的排名代码需要花费大约三天时间,包括编写代码、单元测试和编写文档。接下来,团队需要大约两周的时间来优化代码。其中一项优化是将分数表达式 (simple_gauss(time)* popular )转换为抽象语法树。该团队还实施了高速缓存逻辑,预先计算了将来某些时间的分数。

相比之下,开发这些代码的 Go 版本大约花费了四天时间,并且不需要再对其性能实施进一步的优化。虽然 Python 用来开发初期版本更快,但是整体来说使用 Go 开发的工作量要小得多。

Go 的语言特性使得在优化代码时能够节省大量的时间。使用 Python 时,我们不得不将表达式解析为抽象语法树,并优化和剖析每一个函数。由于 Go 比 Python 快得多,因此我们不需要花太多精力优化代码。最终的结果是,Go 代码的执行速度比精心优化的 Python 代码大约快 40 倍。

用 Go 来构建 Stream 系统中的某些组件相比用 Python 花费了更多的时间。总体来说,开发 Go 代码要花费更多的精力,但团队用来优化代码性能的时间则更少。

结论

Go 非常适用于开发微服务。它的速度非常快,具有原生并发原语,完美支持多种现有工具,并且开发起来乐趣无穷。与 Ruby 或 Python 等脚本语言相比,编写 Go 代码可能需要更长的时间,但其维护成本要低得多,加之其代码无需太多优化,因此你可以节省大量的时间。

需要注意的是,对于某些适合使用 Python 开发的模块,Stream 仍然使用 Python。例如,我们的仪表板、网站以及用于个性化订阅的机器学习都使用 Python 实现,因为 Python 提供的这些工具更好用。我们不会马上完全弃用 Python,但是对于性能要求较高的代码,我们今后会使用 Go 来编写。

原文链接: https://jaxenter.com/stream-switch-go-142279.html

感谢无明对本文的审校。

2018-07-21 18:222811

评论

发布
暂无评论
发现更多内容

GitHub上首本IntelliJ IDEA操作手册,标星果然百万名不虚传

Java 架构 面试 程序人生 编程语言

2021金九银十阿里Java岗7轮技术面经历,险幸上岸

Java 程序员 架构 面试 计算机

这还不够全?阿里P8架构师耗时八年时间才整理出来这“Java核心知识PDF(Java高岗)

Java 程序员 架构 面试 后端

和12岁小同志搞创客开发:如何驱动LED点阵模块?

不脱发的程序猿

少儿编程 创客开发 LED点阵模块

JS的深浅复制,原来如此!

华为云开发者联盟

js 序列化 深复制 浅复制

相约 DTCC 2021 | Tapdata 受邀分享:如何打造面向 TP 业务的数据平台架构

tapdata

深入思考软件工程,开启 DevOps 之旅

BoCloud博云

DevOps cicd 云原生 CI/CD 敏捷交付

汇纳科技数据科学团队研究商场活动效果并优化的论文被ISR期刊接收

网络安全产品之堡垒机应用于金融行业案例讲解

行云管家

云计算 网络安全 等保 堡垒机

2022年最新Java小白学习路线总结,从零基础跟着学习不掉队(PDF+视频分享篇)

Java 编程 程序员 计算机 java面试

面试巨作!13万字!腾讯高工手写JDK源码笔记 带你飙向实战

收到请回复

Java jdk 面试 后端

封神总结!蚂蚁金服+滴滴+美团+拼多多+腾讯15万字Java面试题

收到请回复

Java 程序员 面试 微服务 大厂Offer

理论+实例,带你掌握Linux的页目录和页表

华为云开发者联盟

Linux 内存管理 寄存器 页目录 页表

教育机构这一大堆问题都是由教育管理系统解决的

低代码小观

公司管理 教育 企业管理 CRM 管理工具

阿里P8手抄本惨遭泄露,并出现病毒式传播,致28人斩获大厂offer

收到请回复

Java 面试 阿里 大厂Offer

Android 资源溢出崩溃轻松解

字节跳动终端技术

字节跳动 移动开发 Mars 火山引擎 MARS-APMPlus

从互联网“后来者”到“引领者”:这场IPv6大会上,我读懂了中国式创新

脑极体

会声会影和剪映在音频处理功能上的比较

懒得勤快

马萨卡!阿里大佬珍之若宝的最强高并发pdf,竟然被上传GitHub开源

Java 架构 面试 编程语言

【ShardingSphere技术专题】「ShardingJDBC」(1)带你一同认识一下ShardingJDBC是什么?(高手勿入)

洛神灬殇

ShardingJDBC ShardingSphere 算法学习笔记指南 10月月更

从简历被拒到收割8个大厂offer,我用了3个月成功破茧成蝶

收到请回复

Java 程序员 面试

惊!HUAWEI高工熬夜赶出这本20W字的图解计算机操作系统指南手册,竟被我偶然发现!

Java 架构 面试 程序人生 编程语言

程序员常用的工具软件推荐

程序员小呆

Java c++ 程序员 架构师 Go 语言

手把手带你做LiteOS的树莓派移植

华为云开发者联盟

树莓派 系统 LiteOS arm 树莓派移植

Java集合核心内容之葵花宝面,搞定90%以上的技术面!建议收藏

程序员小呆

Java 程序员 架构师

我凭借这份pdf拿下了蚂蚁金服、字节跳动、小米等大厂的offer

Java 编程 程序员 架构

Zookeeper 集群部署的那些事儿

牧小农

zookeeper

Kubernetes 中的应用参数配置案例详析

Zilliz

数据库 Kuber k8s Helm

极客架构营2期模块5作业

Ping

为什么网络 I/O 会被阻塞?

编程 架构 操作系统 计算机

律所管理系统能解决律师事务所存在的这些问题

低代码小观

公司管理 企业 企业管理 管理工具 律所

Stream从Python切换到Go的原因_Python_Thierry Schellenbach_InfoQ精选文章