NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

从 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:0015697

评论 1 条评论

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

写给 Java 程序员的前端 Promise 教程

江南一点雨

Java spring 前端 springboot Promise

转转商品系统高并发实战(数据篇)

转转技术团队

分布式 高并发

海外邮件发送指南(一)

极光JIGUANG

消息推送 邮件 SendCloud

一名合格的程序员是如何优雅地解决线上问题的?

程序员小毕

Java 程序员 架构 程序人生 后端

跟我一起了解云耀云服务器HECS【华为云至简致远】

IT资讯搬运工

云服务器

面试官:Redis 大 key 要如何处理?

Java永远的神

Java 数据库 redis 程序员 面试

再迎巅峰!阿里爆款分布式小册开源5天Github已73K

冉然学Java

架构 分布式 微服务 java; 编程、

STM32的内存管理相关(内存架构,内存管理,map文件分析)

矜辰所致

内存 stm32 Flash 8月月更

Docker到底是什么,能干什么?这一篇文章全部给你解释清楚了

Java永远的神

Java Docker 程序员 面试 云原生

IT故障快速解决就用行云管家!快速安全!

行云管家

运维 IT运维 行云管家

开源一夏 | 自己画一块ESP32-C3 的开发板(PCB到手)

矜辰所致

开源 硬件设计 8月月更 ESP32-C3

开源一夏 | 使用 JavaScript 和 CSS 做一个图片转 PDF 的转换器

海拥(haiyong.site)

JavaScript 开源 前端 8月月更

C++面向对象友元,全局函数、类、成员函数做友元

CtrlX

8月月更

结合“xPlus”探讨软件架构的创新与变革

BizFree

敏捷开发 软件架构 数字化 信息化 软件定制

游戏开发常遇到数据一致性BUG,怎么解?

华为云开发者联盟

数据库 后端 游戏开发

SpringMVC(一、快速入门)

开源 springmvc 8月月更

电商秒杀系统架构设计

泋清

#架构训练营

RT-Thread记录(三、RT-Thread 线程操作函数及线程管理与FreeRTOS的比较)

矜辰所致

RTT RT-Thread 8月月更 线程操作

国产堡垒机品牌哪家好?功能有哪些?咨询电话多少?

行云管家

运维 堡垒机 运维审计 国产堡垒机 堡垒机品牌

看到这个应用上下线方式,不禁感叹:优雅,太优雅了!

华为云开发者联盟

云计算 开发 CCE

Arco Vue + Flask 手把手实战开发一测试需求平台

MegaQi

测试平台开发教程 签约计划第三季 8月月更

【Redis】redis安装与客户端redis-cli的使用(批量操作)

石臻臻的杂货铺

redis' 8月月更

华为云弹性云服务器ECS使用【华为云至简致远】

IT资讯搬运工

弹性云服务器ECS

直播卖货APP——为何能得到商家和用户的喜欢?

开源直播系统源码

软件开发 语聊房 直播系统 直播源码

设计一个跨平台的即时通讯系统(采用华为云ECS服务器作为服务端 )【华为云至简致远】

IT资讯搬运工

云服务器ECS

手把手教你设计一个全局异常处理器

了不起的程序猿

java程序员 异常处理 java 编程 spring-boot

云原生系列五:Kafka 集群数据迁移基于Kubernetes的内部

叶秋学长

kafka 开源 Kubernetes 8月月更

leetcode 155. Min Stack最小栈(中等)

okokabcd

LeetCode 数据结构与算法 栈和队列

【Redis】位图以及位图的使用场景(统计在线人数和用户在线状态)

石臻臻的杂货铺

redis' 8月月更

客户案例 | 提高银行信用卡客户贡献率

易观分析

金融 银行 分析 客户

从零开始,如何拥有自己的博客网站【华为云至简致远】

IT资讯搬运工

linux 文件权限控制

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