放弃Python转向Go语言:我们找到了以下9大理由


转用一门新语言通常是一项大决策,尤其是当你的团队成员中只有一个使用过它时。今年 Stream 团队的主要编程语言从 Python 转向了 Go。本文解释了其背后的九大原因以及如何做好这一转换。


为什么使用 Go


原因 1:性能


Go 极其地快。其性能与 Java 或 C++相似。在我们的使用中,Go 一般比 Python 要快 30 倍。以下是 Go 与 Java 之间的基准比较:



原因 2:语言性能很重要


对很多应用来说,编程语言只是简单充当了其与数据集之间的胶水。语言本身的性能常常无关轻重。


但是 Stream 是一个 API 提供商,服务于世界 500 强以及超过 2 亿的终端用户。数年来我们已经优化了 Cassandra、PostgreSQL、Redis 等等,然而最终抵达了所使用语言的极限。


Python 非常棒,但是其在序列化/去序列化、排序和聚合中表现欠佳。我们经常会遇到这样的问题:Cassandra 用时 1ms 检索了数据,Python 却需要 10ms 将其转化成对象。


原因 3:开发者效率&不要过于创新


看一下绝佳的入门教程《开始学习 Go 语言》(http://howistart.org/posts/go/1/)中的一小段代码:

package main      
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}

如果你是一个新手,看到这段代码你并不会感到吃惊。它展示了多种赋值、数据结构、指针、格式化以及内置的 HTTP 库。


当我第一次编程时,我很喜欢使用 Python 的高阶功能。Python 允许你创造性地使用正在编写的代码,比如,你可以:


  • 在代码初始化时,使用 MetaClasses 自行注册类别

  • 置换真假

  • 添加函数到内置函数列表中

  • 通过奇妙的方法重载运算符


毋庸置疑这些代码很有趣,但也使得在读取其他人的工作时,代码变得难以理解。


Go 强迫你坚持打牢基础,这也就为读取任意代码带来了便利,并能很快搞明白当下发生的事情。


注意:当然如何容易还是要取决于你的使用案例。如果你要创建一个基本的 CRUD API,我还是建议你使用 Django + DRF,或者 Rails。


原因 4:并发性&通道


Go 作为一门语言致力于使事情简单化。它并未引入很多新概念,而是聚焦于打造一门简单的语言,它使用起来异常快速并且简单。其唯一的创新之处是 goroutines 和通道。Goroutines 是 Go 面向线程的轻量级方法,而通道是 goroutines 之间通信的优先方式。


创建 Goroutines 的成本很低,只需几千个字节的额外内存,正由于此,才使得同时运行数百个甚至数千个 goroutines 成为可能。你可以借助通道实现 goroutines 之间的通信。Go 运行时间可以表示所有的复杂性。Goroutines 以及基于通道的并发性方法使其非常容易使用所有可用的 CPU 内核,并处理并发的 IO——所有不带有复杂的开发。相较于 Python/Java,在一个 goroutine 上运行一个函数需要最小的样板代码。你只需使用关键词「go」添加函数调用:

package main   
import  (   
        "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" )}

Go 的并发性方法非常容易上手,相较于 Node 也很有趣;在 Node 中,开发者必须密切关注异步代码的处理。


并发性的另一个优质特性是竞赛检测器,这使其很容易弄清楚异步代码中是否存在竞态条件。下面是一些上手 Go 和通道的很好的资源:


  • https://gobyexample.com/channels

  • https://tour.golang.org/concurrency/2

  • http://guzalexander.com/2013/12/06/golang-channels-tutorial.html

  • https://www.golang-book.com/books/intro/10

  • https://www.goinggo.net/2014/02/the-nature-of-channels-in-go.html


原因 5:快速的编译时间


当前我们使用 Go 编写的最大微服务的编译时间只需 6 秒。相较于 Java 和 C++呆滞的编译速度,Go 的快速编译时间是一个主要的效率优势。我热爱击剑,但是当我依然记得代码应该做什么之时,事情已经完成就更好了。


Go 之前的代码编译


原因 6:打造团队的能力


首先,最明显的一点是:Go 的开发者远没有 C++和 Java 等旧语言多。据知,有 38% 的开发者了解 Java,19.3% 的开发者了解 C++,只有 4.6% 的开发者知道 Go。GitHub 数据表明了相似的趋势:相较于 Erlang、Scala 和 Elixir,Go 更为流行,但是相较于 Java 和 C++ 就不是了。


幸运的是 Go 非常简单,且易于学习。它只提供了基本功能而没有多余。Go 引入的新概念是「defer」声明,以及内置的带有 goroutines 和通道的并发性管理。正是由于 Go 的简单性,任何的 Python、Elixir、C++、Scala 或者 Java 开发者皆可在一月内组建成一个高效的 Go 团队。


原因 7:强大的生态系统


对我们这么大小的团队(大约 20 人)而言,生态系统很重要。如果你需要重做每块功能,那就无法为客户创造收益了。Go 有着强大的工具支持,面向 Redis、RabbitMQ、PostgreSQL、Template parsing、Task scheduling、Expression parsing 和 RocksDB 的稳定的库。


Go 的生态系统相比于 Rust、Elixir 这样的语言有很大的优势。当然,它又略逊于 Java、Python 或 Node 这样的语言,但它很稳定,而且你会发现在很多基础需求上,已经有高质量的文件包可用了。


原因 8:GOFMT,强制代码格式


Gofmt 是一种强大的命令行功能,内建在 Go 的编译器中来规定代码的格式。从功能上看,它类似于 Python 的 autopep8。格式一致很重要,但实际的格式标准并不总是非常重要。Gofmt 用一种官方的形式规格代码,避免了不必要的讨论。


原因 9:gRPC 和 Protocol Buffers


Go 语言对 protocol buffers 和 gRPC 有一流的支持。这两个工具能一起友好地工作以构建需要通过 RPC 进行通信的微服务器(microservices)。我们只需要写一个清单(manifest)就能定义 RPC 调用发生的情况和参数,然后从该清单将自动生成服务器和客户端代码。这样产生代码不仅快速,同时网络占用也非常少。


从相同的清单,我们可以从不同的语言生成客户端代码,例如 C++、Java、Python 和 Ruby。因此内部通信的 RESET 端点不会产生分歧,我们每次也就需要编写几乎相同的客户端和服务器代码。


使用 Go 语言的缺点


缺点 1:缺少框架


Go 语言没有一个主要的框架,如 Ruby 的 Rails 框架、Python 的 Django 框架或 PHP 的 Laravel。这是 Go 语言社区激烈讨论的问题,因为许多人认为我们不应该从使用框架开始。在很多案例情况中确实如此,但如果只是希望构建一个简单的 CRUD API,那么使用 Django/DJRF、Rails Laravel 或 Phoenix 将简单地多。


缺点 2:错误处理


Go 语言通过函数和预期的调用代码简单地返回错误(或返回调用堆栈)而帮助开发者处理编译报错。虽然这种方法是有效的,但很容易丢失错误发生的范围,因此我们也很难向用户提供有意义的错误信息。错误包(errors package)可以允许我们添加返回错误的上下文和堆栈追踪而解决该问题。


另一个问题是我们可能会忘记处理报错。诸如 errcheck 和 megacheck 等静态分析工具可以避免出现这些失误。虽然这些解决方案十分有效,但可能并不是那么正确的方法。


缺点 3:软件包管理


Go 语言的软件包管理绝对不是完美的。默认情况下,它没有办法制定特定版本的依赖库,也无法创建可复写的 builds。相比之下 Python、Node 和 Ruby 都有更好的软件包管理系统。然而通过正确的工具,Go 语言的软件包管理也可以表现得不错。


我们可以使用 Dep 来管理依赖项,它也能指定特定的软件包版本。除此之外,我们还可以使用一个名为 VirtualGo 的开源工具,它能轻松地管理 Go 语言编写的多个项目。



Python vs Go


我们实施的一个有趣实验是用 Python 写排名 feed,然后用 Go 改写。看下面这种排序方法的示例:

{   
"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(time)*popularity 字符串转变为一种函数,能够把 activity 作为输入然后给出得分作为输出。

  2. 在 JSON config 上创建部分函数。例如,我们想要「simple_gauss」调用「decay_gauss」,且带有的键值对为"scale": "5d"、"offset": "1d"、"decay": "0.3"。

  3. 解析「defaults」配置,便于某个领域没有明确定义的情况下有所反馈。

  4.  从 step1 开始使用函数,为 feed 中的所有 activity 打分。


开发 Python 版本排序代码大约需要 3 天,包括写代码、测试和建立文档。接下来,我么花费大约 2 周的时间优化代码。其中一个优化是把得分表达 simple_gauss(time)*popularity 转译进一个抽象语法树。我们也实现了 caching logic,之后会预先计算每次的得分。


相比之下,开发 Go 版本的代码需要 4 天,但之后不需要更多的优化。所以虽然最初的开发上 Python 更快,但 Go 最终需要的工作量更少。此外,Go 代码要比高度优化的 python 代码快了 40 多倍。


以上只是我们转向 Go 所体验到的一种好处。当然,也不能这么做比较:


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

  • Go 代码是在 Python 代码之后写的,所以提前理解了该案例;

  • Go 的表达解析库质量优越。


Elixir vs Go


我们评估的另一种语言是 Elixir。Elixir 建立在 Erlang 虚拟机上。这是一种迷人的语言,我们之所以想到它是因为我们组员中有一个在 Erlang 上非常有经验。


在使用案例中,我们观察到 Go 的原始性能更好。Go 和 Elixir 都能很好地处理数千条并行需求,然而,如果是单独的要求,Go 实际上更快。相对于 Elixir,我们选择 Go 的另一个原因是生态系统。在我们需求的组件上,Go 的库更为成熟。在很多案例中,Elixir 库不适合产品使用。同时,也很难找到/训练同样使用 Elixir 的开发者。


结论


Go 是一种非常高效的语言,高度支持并发性。同时,它也像 C++和 Java 一样快。虽然相比于 Python 和 Ruby,使用 Go 建立东西需要更多的时间,但在后续的代码优化上可以节省大量时间。在 Stream,我们有个小型开发团队为 2 亿终端用户提供 feed 流。对新手开发者而言,Go 结合了强大的生态系统、易于上手,也有超快的表现、高度支持并发性,富有成效的编程环境使它成为了一种好的选择。Stream 仍旧使用 Python 做个性化 feed,但所有性能密集型的代码将会用 Go 来编写。


来源:机器之心

作者:Thierry Schellenbach,机器之心编译,参与:黄小天、李亚洲

原文地址:https://getstream.io/blog/switched-python-go/


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/304783.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开源许可证的变更带给我们什么启示?

喜欢就关注我们吧&#xff01;近日&#xff0c;Elastic 公司将旗下的知名开源项目 Elasticsearch 和 Kibana 的开源许可证变更的事件持续发酵&#xff0c;再次把我们的目光聚焦到开源公司与云服务厂商之间的矛盾旋涡中。事实上&#xff0c;Elastic 公司与云服务厂商的“积怨”由…

as本地仓库更改_将gitee仓库连接GitHub Desktop。新建更改仓库并上传至gitee。

Ⅰ、在GitHub Desktop上登陆账号GitHub Desktop上只能用GitHub账户登陆第一次打开GitHub Desktop使会直接有登陆界面出现的&#xff0c;直接用GitHub的账户登陆就好了可以在最上方的菜单&#xff0c;File → Options打开页面登陆 &#xff08;详细操作见图&#xff09;这是已经…

有人问我:程序员要供祖师爷的话该供谁?

有人问我&#xff1a;程序员是不是都抽烟&#xff1f; 我想了半天我抽烟完全是因为医生&#xff0c;在我刚上大学的时候还不会吸烟&#xff0c;有一天嗓子特别疼&#xff0c;我就去医院检查&#xff0c;大夫检查之后对我说&#xff0c;没什么太大毛病&#xff0c;你少抽点烟就行…

java父类转子类_java中什么是继承,和继承的接口的关系?

继承的概念继承是java面向对象编程技术的一块基石&#xff0c;因为它允许创建分等级层次的类。继承就是子类继承父类的特征和行为&#xff0c;使得子类对象&#xff08;实例&#xff09;具有父类的实例域和方法&#xff0c;或子类从父类继承方法&#xff0c;使得子类具有父类相…

VSCode+BeetleX.VueHost开发Vue应用

BeetleX.VueHost是一个用于打包Vue和提供HTTP服务的程序&#xff0c;它能提供在没安装vue-cli和webpack的情况下开发vuejs应用。使用 BeetleX.VueHost无须安装下载运行即可&#xff0c;可以通过以下地址下载&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1z4Jfz…

8 无法识别raid盘_王者荣耀防沉迷规则再升级;未来将采用人脸识别验证

昨天&#xff0c;《王者荣耀》官网发布了《未成年人防沉迷新规接入公告》&#xff0c;这份公告对于未成年人的可游玩时长、充值金额等都做出了规定。规则规定&#xff1a;在游玩时长方面&#xff0c;未成年用户每日22时至次日8时禁玩&#xff0c;法定节假日每日限玩3小时&#…

干货|MIT线性代数课程精细笔记[第二课]

0前言 MIT线性代数课程精细笔记[第一课]笔记见MIT线性代数课程精细笔记[第一课]。 该笔记是连载笔记&#xff0c;希望对大家有帮助。 1知识概要 这一节中我们介绍一下消元法&#xff0c;即是上一节中我们提到的“系统化”求解方程所用的方法&#xff0c;通过矩阵消元运算可以很…

在以下说法错误的是_外行人对翡翠有哪些错误认知?行家给你最精准的答案

玉石行业虽然在我们国家有着很悠久的历史&#xff01;但是就行业认知而言&#xff0c;仍然属于小众行业。正所谓隔行如隔山&#xff0c;在很多外行人眼里&#xff0c;翡翠行业很神秘&#xff0c;而且水也很“深”&#xff01;甚至很多人认为这个行业“三年不开张&#xff0c;开…

参加美赛,需掌握这些算法和模型

昨天晚上的直播甚是精彩 方同学不但分享了 获奖论文、解题技巧 还分享了 赛前准备、比赛经验和日程规划 po几张截图让大家感受下 此时此刻可能会有不少童鞋 正在为错过直播而懊悔 不用担心 超模君又准备了一份豪华大礼 本周 超模君特意邀请到 今年美赛A题特等奖获奖者 徐乾同学…

yii 使用 有赞sdk_有赞ABTest系统:数据驱动增长实践

‍‍点击关注“有赞coder”获取更多技术干货哦&#xff5e;作者&#xff1a;子固部门&#xff1a;数据中台一、背景有赞是一个商家服务公司&#xff0c;致力于帮助每一位重视产品和服务的商家成功。随着移动互联网的流量增长红利渐渐褪去&#xff0c;商家获得新的流量越来越困难…

分布式数字签名令牌TokenProvider

在分布式系统中&#xff0c;令牌签发系统往往需要跟令牌应用系统分离&#xff0c;并且应用系统可以独立验证令牌&#xff0c;无需请求签发系统接口。数字签名令牌属于发明专利《基于令牌协议的令牌组网构建方法》&#xff08;已授权专利号201510213377.X&#xff09;的一部分&a…

热力地图高德_高德地图:最新动态

高德地图是国内最专业的手机地图&#xff0c;超过3.2亿用户在使用&#xff01;高德地图是应用商店上数据准确率最高、最省流量、躲避拥堵功能最强大的手机地图&#xff0c;平均每天为用户省油61万升&#xff01;高德地图今日宣布上线货车导航功能&#xff0c;帮助全国3000万货车…

有效处理 Java 异常三原则

Java中异常提供了一种识别及响应错误情况的一致性机制&#xff0c;有效地异常处理能使程序更加健壮、易于调试。 异常之所以是一种强大的调试手段&#xff0c;在于其回答了以下三个问题&#xff1a; 什么出了错? 在哪出的错? 为什么出错? 在有效使用异常的情况下&#x…

人口危机 资本剥削导致生育率低迷

不久前&#xff0c;相关部门公布数据&#xff0c;2020年出生并已经到公安机关进行户籍登记的新生儿共1003.5万。对此&#xff0c;铁流先不做评论&#xff0c;我们先看数据。以下是1949年和1981年以来人口出生情况&#xff1a;1949年: 1275万......1981年&#xff1a;2064万1982…

连不上网_手机连不上网?四种方法教你如何解决,建议收藏以备不时之需

随着科技的进步&#xff0c;现在家家户户大街小巷都是Wifi信号&#xff0c;所以无线基地已经成为生活中不可缺少的一环&#xff0c;但也因为这样无线干扰的情况&#xff0c;常常听到有人抱怨怎么无线又突然断线啦&#xff1f;我的wifi又连不上了&#xff1f;为什么无线上网速度…

关于机器学习,你应该至少学习这8个落地案例|干货集锦

机器学习、深度学习、强化学习、迁移学习&#xff0c;这些你到底了解多少&#xff1f;各种深度学习框架如TensorFlow、Caffe、MXNet等又该如何选择&#xff1f;如何将机器学习整合到正在开发的应用中&#xff1f;机器学习在金融、电商、外卖、教育等领域有哪些落地案例&#xf…

c++经典编程题_全国青少年软件编程等级考试C语言经典程序题10道十

全国青少年软件编程等级考试C语言经典程序题10道十【程序91】题目&#xff1a;时间函数举例11.程序分析&#xff1a;2.程序源代码&#xff1a;#include "stdio.h"#include "time.h"void main(){ time_t lt; /*define a longint time varible*/lttime(NULL)…

使用SQL Server分区表功能提高数据库的读写性能

首先祝大家新年快乐&#xff0c;身体健康&#xff0c;万事如意。一般来说一个系统最先出现瓶颈的点很可能是数据库。比如我们的生产系统并发量很高在跑一段时间后&#xff0c;数据库中某些表的数据量会越来越大。海量的数据会严重影响数据库的读写性能。这个时候我们会开始优化…

回顾周杰伦17年间的歌词,才知道他都唱了些什么

每当提到周杰伦的歌时&#xff0c;你首先会想到的是什么呢&#xff1f;双截棍&#xff1f;中国风&#xff1f;还是是方文山&#xff1f;或者更会有人回答说&#xff1a;根本听不清的歌词…… 回想起来&#xff0c;周杰伦的歌可以说陪伴了我们一代甚至是几代人的成长。无论是《晴…

最近公共祖先_[LeetCode] 236. 二叉树的最近公共祖先

题目链接&#xff1a; https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree难度&#xff1a;中等通过率&#xff1a;57.2%题目描述:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。百度百科中最近公共祖先的定义为&#xff1a;"对于有根树…