AICon上海|与字节、阿里、腾讯等企业共同探索Agent 时代的落地应用 了解详情
写点什么

从 Python 切换到 Go 的 9 个理由

  • 2020-04-16
  • 本文字数:4832 字

    阅读完需:约 16 分钟

从Python切换到Go的9个理由

切换到一种新的编程语言通常是一件大事,特别是当团队成员对原始语言有丰富经验时。今年年初,Stream将其主要编程语言从 Python 切换到了 Go。本文将会解释他们决定从 Python 切换到 Go 的一些原因。

使用 Go 的理由

理由 1:性能


Go 非常快。它的性能接近 Java 或 C。Go 的速度比 Python 快 30 倍。

理由 2:语言本身的性能很重要

对于许多应用程序而言,编程语言只是应用程序和数据库之间的粘合剂。语言本身的性能通常并不重要。


Stream 是一家 API 提供商,它为 500 家公司和超过 2 亿的最终用户提供了反馈基础设施。多年来,我们一直在优化 Cassandra、PostgreSQL、Redis 等软件的性能,但是现在我们已经达到了我们所使用编程语言的极限。


Python 是一门伟大的语言,但是对于序列化/反序列化、排序和聚合等示例,它的性能非常差。我们经常会遇到性能问题,Cassandra 花费 1ms 的时间来检索数据,而 Python 将其转换成对象则需要 10ms 的时间。

理由 3:开发人员的效率,而无需太多创新

请看下“如何开始学习Go”教程中的如下 Go 代码片段。


type openWeatherMap struct{}func (w openWeatherMap) temperature(city string) (float64, error) {    resp, err := http.Get("http://api.openweathermap.org/data/2.5/weather?APPID=YOUR_API_KEY&q=" + city)    if err != nil {        return 0, err    }    defer resp.Body.Close()    var d struct {        Main struct {            Kelvin float64 `json:"temp"`        } `json:"main"`    }    if err := json.NewDecoder(resp.Body).Decode(&d); err != nil {        return 0, err    }    log.Printf("openWeatherMap: %s: %.2f", city, d.Main.Kelvin)    return d.Main.Kelvin, nil}
复制代码


如果你刚开始学习 Go,阅读这段代码不会有太多惊喜。它演示了赋值、数据结构、指针、格式化和内置的 HTTP 库。


从我首次接触编程开始,我总是喜欢使用 Python 的高级特性。 Python 使我们能从正在编写的代码中获得很好的想法。例如,我们可以:


  • 初始化代码时,使用元类(MetaClasses)自己注册类

  • 切换“True”和“False”

  • 将一个函数添加到内置函数列表中

  • 通过魔术方法(Magic Method)重载运算符


这些特性非常有趣,但是,大多数程序员都认为这会增加阅读他人代码的难度。


Go 会迫使我们使用最基本的东西,这使得阅读他人代码变得更容易。


注:当然,“容易”取决于具体的项目。如果只是创建一个基本的 CRUD API,我仍然建议使用 Django&DRF或 Rails。

理由 4 :并发和通道

作为一门编程语言,Go 总是尽可能地保持简单。它没有引入太多的新概念,因为它的目标是创建一门易于使用的编程语言。它唯一具有创新性的地方是 Goroutines(go 协程)和 Channels(通道)。 Goroutines 是 Go 的轻量级线程解决方案,而 Channels 是与 Goss 交互的首选方式。


Goroutines 非常轻量,仅需要几千字节的额外内存。而且由于 Goroutine 如此轻量,因此可以同时运行数百甚至数千个 Goroutine。


我们可以使用 Channels 在 Goroutines 之间进行通信。Go 运行时处理所有的内部复杂性。基于 Goroutines 和 Channels 的并发方案使应用程序能够轻松使用所有可用的 CPU 内核并处理并发 IoO,而无需进行复杂的开发。与 Python/Java 相比,在 Goroutines 上运行函数只需要很少的固定代码。我们只需要使用关键字“go”调用函数即可:


package mainimport (    "fmt"    "time")func say(s string) {    for i := 0; i < 5; i++ {        time.Sleep(100 * time.Millisecond)        fmt.Println(s)    }}func main() {    go say("world")    say("hello")}
复制代码


https://tour.golang.org/concurrency/1


Go 的并发解决方案非常易于使用。与开发人员必须密切关注异步代码处理方式的 Node 相比,这是一个非常有趣的方案。


Go 并发的另一个关注点是竞态检测。它使应用程序能够很容易地知道异步代码中是否存在任何竞态条件。


以下是一些学习 Go 和 Channels 的重要资源:


理由 5:编译速度快

用 Go 编写的最大的微服务项目只需 6 秒就可以编译完成。与 Java 和 C 等语言的龟速(turtle-speed)编译相比,Go 的极快编译速度是它的主要生产力。

理由 6:组件团队的能力

让我们从这些数据开始:Go 的开发人员没有 C 和 Java 的开发人员多。根据StackOverflow的统计,有 38%的开发人员使用 Java,19.3%的开发人员使用 C,但只有 4.6%的开发人员使用 Go。 GitHub数据也显示出了类似的趋势:Go 比 Erlang、Scala 和 Elixir 等语言使用得更广泛,但不如 Java 和 C 那么流行。


幸运的是,Go 是一门非常简单易学的语言。它只提供了我们需要的基本功能,而没有提供其他附加功能。它引入了一些新概念,例如“defer”声明和内置的“go routines”以及 Channels 并发管理等。团队中的任何 Python、Elixir、C、Scala 或 Java 开发人员都可以在一个月内学习会怎么使用 Go 编程,因为 Go 非常简单。


与其他语言相比,我们发现建立 Go 开发团队更加容易。如果我们在竞争激烈的环境中(例如在博尔德和阿姆斯特丹)招聘,这是一个非常重要的优势。

理由 7:强大的生态系统

生态系统对于我们这样规模的团队(大约 20 人)来说非常重要。如果你不得不重新设计所有的功能,你就不能为你的客户创造价值。Go 为我们经常使用的工具提供了强大的支持。例如,Redis、RabbitMQ、PostgreSQL、模板解析、任务调度、表达式解析和 DBRocks 都可以使用现有的库。


与其他新语言(例如 Rust 或 Elixir)相比,Go 具有巨大的生态系统优势。尽管它不能与 Java、Python 或 Node 相提并论,但是我们是可以找到许多能够满足基本需求的高质量软件包。

理由 8:Gofmt,强制代码格式化

Gofmt 是一个优秀的命令行程序,它内置于 Go 编译器中,可用于格式化代码。在功能方面,它类似于 Python 的 autopep 8。我们大多数人都不喜欢争论制表符(tabs)和空格(spaces),但格式化的目标始终是一致的,实际的格式标准则无关紧要。Gofmt 以一种形式化的方式来格式化代码,以避免所有这些争论。

理由 9:gRPC 以及 Protocol Buffers

Go 为 Protocol Buffers 和 gRPC 提供了一流的支持。它将这两个工具完美地结合在一起,构建了一个通过 RPC 进行通信的微服务。我们只需编写一个定义了 RPC 调用及其参数的清单文件,服务端和客户端就可以据此自动生成适当的代码了。这不仅速度快,而且网络占用空间小,使用起来更方便。


其他语言(如 C、Java、Python 和 Ruby)中的客户端代码也可以基于相同的清单文件生成。这样,就不会与内部 REST 接口发生冲突了,而且我们也不必每次都编写几乎相同的客户端和服务端代码。

使用 Golang 的缺点

缺点 1 :缺乏框架

Go 不像 Ruby 的 Rails、Python 或 Django 或 PHP 的 Laravel,它没有一个主要的框架。这个话题在 Go 社区引起了激烈的争论,许多人认为不应该使用现有的框架来启动项目。在某些情况下,我完全同意这一点。但是,如果我们想要构建一个简单的 CRUD API,那么使用 Django/DJRF、Rails Laravel 或Phoenix则会更简单。

缺点 2:错误处理

Go 通过简单地从函数中返回错误的形式来处理错误。尽管这种方案是可行的,但是它很容易失去错误的范围,从而很难向用户提供有价值的错误信息。错误包可以通过返回错误的上下文和错误堆栈来解决该问题。


还有一个问题,那就是它很容易忘记去处理错误。尽管诸如 errcheck 和 megacheck 之类的静态分析工具可以避免这些错误,但这始终并不完善。也许我们应该期待一种语言级别的错误处理方案。

缺点 3:包管理

Go 的包管理并不完善。默认情况下,它无法指定依赖项的特定版本,也无法创建可重用的构建方案。 Python、Node 和 Ruby 都有更好的包管理系统。但是,如果能使用正确的工具,Go 的包管理也可以变得更简单。


我们可以使用Dep来管理指定固定版本的依赖项。此外,我们还提供了一个名为VirtualGo的开源工具,用于多项目管理。

Python vs Go

我们做了一个有趣的实验,用 Go 重写了原来由Python编写的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"}
复制代码


Python 和 Go 的代码都需要执行如下操作来支持此排序方法:


  1. 解析分数表达式,将“simple_gauss”转换为函数,输入活动并输出分数

  2. 通过 JSON 配置创建函数。例如,我们想要“simple_gauss”在 scale 为 5 天、offset 为 1 天、factor 为 0.3 时调用“decay_gauss”。

  3. 当字段没有值时,解析“defaults”配置并采用默认值。

  4. 从步骤 1 开始使用该函数,对 feed 中的所有活动进行评分。


开发 Python 版的排序(Sort )代码花了大约三天的时间,其中包括代码编写、单元测试和文档编写。接下来,我们花了大约 2 周的时间来优化代码。其中一种优化方法是将分数表达式 simple_gauss(time)*popularity 转换为抽象语法树。我们还实现了可用于预测分数的缓存逻辑。


相比之下,开发此代码的 Go 版花了大约四天的时间,并且在后期不需要进一步地优化性能。因此,尽管 Python 最初的开发速度更快,但是 Go 版最终需要的工作量更少。另一个优势是,Go 代码比我们高度优化的 Python 代码还要快 40 倍。


当然,这只是说明我们切换到 Go 后性能提升的一个简单示例:


  • 排序代码是我用 Go 编写的第一个项目。

  • Go 代码是在 Python 代码之后编写的,因此对项目的理解更加深入。

  • Go 的表达式解析库的质量更高


你的经历可能会有所不同。与 Python 相比,使用 Go 构建系统中的某些其他组件需要花费更多的时间。通常,编写 Go 代码需要付出更多的努力。但是,优化代码性能所需的时间会更少。

Elixir vs Go

我们想要评估的另一种语言是Elixir。 Elixir 是一门建立在 Erlang 虚拟机上的引人入胜的语言。我之所以这么说,是因为我们的一个项目团队非常精通该语言。


出于这个原因,我们注意到 Go 的原始性能更好。 Go 和 Elixir 都能支持数千个并发请求。但是,如果我们查看单个请求的性能,Go 要快得多。我们选择 Go 的另一个原因是它的生态系统。 对于我们需要的组件来说,Go 具有更成熟的库,而 Elixir 尚不适合用于生产。同时,也很难招聘到 Elixir 开发人员或对开发人员进行 Elixir 培训。

结论

Go 是一种性能非常高的语言,并且它对并发的支持非常强大。它差不多与 C 和 Java 一样快了。尽管 Go 的编译速度比 Python 或 Ruby 慢,但我们可以节省出大量的优化代码时间。


Go 对于新手而言具有庞大的生态系统,它易于学习使用,具有超高的性能,并且对并发有强大的支持,此外,它还具有非常高效的开发环境。这些特性使 Go 成为开发人员最合适的选择。


如果你想要了解更多关于 Go 的信息,请阅读下面列出的文章。如果想了解更多关于 Stream 的信息,请浏览此交互式教程


相关阅读:



Go 学习资料:



原文链接:


Nine reasons to switch from Python to Go


2020-04-16 09:0016049

评论 1 条评论

发布
用户头像
emmm '缺点 3:包管理' 现在有go modules
2020-04-24 17:00
回复
没有更多了
发现更多内容

我,第一次做项目经理,干赔了

四猿外

智慧政务,区块链电子证照平台的解决方案

13828808769

#区块链#

图尔兹与达梦数据库达成全面战略合作,共筑国产数据库新生态

BinTools图尔兹

数据库 数据安全 操作数据库

「架构实战营」作业#1

高亮

私有依赖的打包与上传

blueju

JavaScript 大前端 npm

MySQL-技术专题-Lock入门到精通

码界西柚

MySQL lock

MVVP:一种基于状态的架构模式的设计与实现

行者

站在巨人的肩膀上!淘宝网Java千亿级并发系统架构设计笔记

Java架构追梦

Java 架构 亿级并发 淘宝网

字节跳动上亿级别秒杀系统优化,用这个方案可行吗?

Java架构师迁哥

通俗易懂数仓建模—Inmon范式建模与Kimball维度建模

五分钟学大数据

数据仓库 维度建模 4月日更 范式建模

第 0 期架构训练营模块 1 作业

架构实战营

Pod 的状态

耳东@Erdong

容器 4月日更

SARIF在应用过程中对深层次需求的实现

华为云开发者联盟

DevSecOps 元数据 SARIF 软件安全 规则

物联网设备天线设计与选型指南

不脱发的程序猿

物联网 4月日更 物联网设备天线 天线设计与选型指南 射频

Ubuntu 鼠标手势软件 -- EasyStroke

TroyLiu

Linux ubuntu 效率 快捷键 鼠标手势

【架构实战营】第1模块作业

swordman

架构实战营

【LeetCode】删除有序数组中的重复项 IIJava题解

Albert

算法 LeetCode 4月日更

尤雨溪:Vue 3 将不会支持 IE11 了

清秋

翻译 Vue 4月日更 IE

“区块链+电子证照”,推动数字化经济建设

电微13828808271

区块链+ #区块链#

架构实战营模块1作业

季节风myy

区块链药品防伪溯源平台搭建,区块链防伪溯源的解决方案

13828808769

#区块链#

Thrift 学习笔记

U2647

Thrift 4月日更

生活中的这些难题,数据库开发者可为你解决!

华为云开发者联盟

数据库 开发者 华为云 GaussDB(for Redis) Redis Stream

Baas是什么?区块链Baas平台开发解决方案带你知晓

源中瑞-龙先生

区块链 开发 解决方案 Baas

在微前端中,antd icon createFormIconfontCN 的本地化问题

blueju

大前端 antd umijs

WordPress中常用的8个函数

Sakura

4月日更

京东云智臻链开源两周年,JD Chain领跑国内自研区块链技术

京东科技开发者

区块链

「免费开源」基于Vue和Quasar的crudapi前端SPA项目实战—环境搭建 (一)

crudapi

Vue nodejs crudapi quasar SPA

浅谈一个优秀的 Android SDK 需要具备哪些要点

神策技术社区

android 数据采集 sdk 神策数据

“智慧旅游”:区块链能否驾驭文旅行业?

电微13828808271

智慧公安

IDEA实用快捷建

华血

从Python切换到Go的9个理由_编程语言_Shiv McIntyre_InfoQ精选文章