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