Python 开发者在迁移到 Go(lang) 时须要知道哪些事?

【编者按】本文最先由 Repustate 发布,主要介绍将代码迁移至 Go(lang) 时的注意事项。文章系国内 ITOM 管理平台 OneAPM 编译呈现,如下为正文。html

这是一篇讲述将大块 Python/Cython 代码迁移到 Go 的长文章。若是你想了解整个事情的通过、背景等全部信息,请读下去。若是你只对 Python 开发者须要了解的事感兴趣,请下拉到早该知道的事板块。python

背景

咱们在 Repustate 最大的技术成果就是实现了阿拉伯语情感分析。阿拉伯语是个难啃的硬骨头,由于阿拉伯语词汇的形式很是复杂。阿拉伯语的标记化(把一句话拆分红单个单词)也比英语要可贵多,由于阿拉伯单词内部可能会包含空格(例如单词内部“aleph”的位置)。在不泄露机密的状况下,Repustate 利用支持向量机(SVM)来获取一个句子最可能的意思,而且以此来推断句子的情感。咱们一共采用了22种模型(22个支持向量机),文档中的每一个词都会被分析。也就是说,若是一个文档包含500个词,就会与支持向量机进行10000屡次对比。golang

Python

Repustate 几乎彻底是用 Python 搭建的,咱们使用 Django 来搭建 API 接口和网站架构。所以,为了保持代码一致性,使用 Python 来实现全部阿拉伯语情感引擎才说得通。就原型设计和实现流程而言,Python 依然是一个很好的选择:表现能力优秀,又有强大的第三方库资源,等等。若是是服务于网页,它就是最佳选择。若是是稍低级别的运算,须要与哈希表(Python 中的字典)进行大量对比时,运行速度就会慢下来。咱们一秒钟只能处理2到3个阿拉伯语单词,这种速度太慢了。相比之下,咱们的英语情感引擎每秒能处理500个单词。django

瓶颈

所以,咱们启动了 Python 分析器,开始调查速度慢的缘由。还记得上文提到咱们有22个支持向量机,每一个单词都会经过它们处理吗?原来这个过程是按顺序进行,而不是并行的。好了,第一个想法是换成相似分布式计算系统(map/reduce)的处理器。长话短说:Python 不适合用 map/reduce。当你须要并发性的时候,Python 并不能帮上忙。在 Pycon 2013大会中,Guido 谈到了 Tulip,他但愿用来解决这个问题的一个新项目,可是还要过一段时间才能发布。但是,若是已经有了更好的选择,为何还要苦等下去呢?编程

选择 Golang 仍是回老家(Go Home)

在 Mozilla 的朋友告诉笔者,Mozilla 服务的日志架构大部分代码都已迁移到 Go,部分缘由是 goroutines 超级便利。Go 是由谷歌员工开发的,设计之初就将并发需求列为一级理念,而不是像 Python 的众多解决方案同样在作过后补救。所以咱们开始着手实现从 Python 到 Go 的迁移。json

虽然 Go 代码还没实现大规模产出,获得的结果已经很是振奋人心。咱们如今一秒钟能处理1000个文档,使用的内存大大减小,并且也不用再去调试和解决使用 Python 时会遇到的多进程/协程(gevent)/“为何 Control-C 杀死了个人进程”等问题。数组

喜欢 Go 的缘由

任何略懂编程语言的人(明白解释与编译、动态与静态区别)都会说:“哈,显然 Go 要快多了。”没错,咱们是能够用 Java 重写全部内容,而且取得相似的效果,可是这并非 Go 胜出的缘由。你用 Go 写的代码彷佛一出来是正确的。笔者也说不清楚,可是不知怎么的,一旦代码被编译(编译过程很是迅速),你就会感受它能工做了(不仅是运行不出错,并且还逻辑正确)。这听起来很含糊,可是它是真的。在冗余或无冗余方面,它跟 Python 类似,它把函数当作一级对象,所以函数编程很方便。并且毋庸置疑,goroutines 和 channels 会让你更加省心省力。静态类型还会带来极大的性能提高,以及更精确的内存分配控制,可是又不会损失太多表达性。数据结构

早该知道的事

除去溢美之词,跟 Go 打交道须要与 Python 彻底不一样的一套思惟模式。如下列出的是笔者在迁移时作的一些笔记——都是在从 Python 迁移到 Go 时随机想到的一些东西:架构

  • 没有内建的集合类型(须要使用 map,而后测试存在性)并发

  • 因为没有集合类型,须要本身写代码来实现交集、并集等方法

  • 无元组(tuple),必须本身写架构或使用切片(slice)(数组)

  • 没有相似 getattr_() 的方法,所以须要不断检查存在性,而不能像在 Python 中那样设置缺省值:value = dict.get(“a_key”, “default_value”)

  • 必须不断检查错误(至少须要显式忽略它们)

  • 不能包含未使用的变量或包,所以有时候若是要测试一些简单问题,须要给代码添加注释

  • 在 []byte 和 string 之间切换。正则表达 (regexp) 使用 []byte (可变)。这说得通,可是在一些变量之间来回切换仍是很烦人

  • Python 更为宽松。你能够用超出范围的索引来索取字符串片断,也不会有什么问题,还能够提取负值片断,可是 Go 就不行

  • 不能使用混合类型的数据结构。也许不合规定,可是有时候在 Python 可使用混合字符串和列表的字典。在 Go 就不行,要么清理干净数据结构,要么自定义结构。感谢 Ralph Corderoy 向笔者展现了如何正确操做(用这个界面,卢克)
    http://play.golang.org/p/SUgl7wd9tk

  • 不能把元组或列表分解成分开的变量(如 x,y,x = [1,2,3])

  • 驼峰字规则(UpperCamelCase)(若是一个包中的函数或结构首字母未大写,就不会暴露给其余包)。笔者更喜欢 Python 的小写加下划线格式(lower_case_with_underscores)

  • 须要显式检查错误是否为 != nil,不像 Python 有不少类型能够用于布尔型检查(0,“”,None 都会被解读为“假”)

  • 某些模块(如 crypto/md5)的文档不足,可是 IRC 上面的 go-nuts 很是棒,拥有特别好的支持

  • 从数字到字符串的类型转换(int64 -> 字符串)跟[]byte -> 字符串(只用字符串([]byte))不一样,须要用到 strconv

  • Go 的代码读起来更像是编程语言,而 Python写出来更像伪代码。Go 包含更多非数字字母字符,用 || 和 && 来表示“或”与“和”

  • 写文件会有 File.Write([]byte) 和File.WriteString(string),这会让习惯了 Python
    只有一种作事方法的开发者们有些不适应

  • 字符串插入很麻烦,不得不常用 fmt.Sprintf

  • 没有构造函数,常见的作法是建立 NewType() 函数,来返回你须要的结构

  • Else 或 else if 必须格式正确,else 得跟 if 从句的大括号在一行。这很奇怪。

  • 根据函数内外位置,使用不一样的赋值操做符,例如 = 和 :=

  • 若是只想要相似dict.keys() 或dict.values()获得的键值或取值列表,或者经过

  • dict.items()获得的元祖列表,在 Go 里面是没法实现的,只能自行迭代 map,而后建立本身的列表

  • 笔者习惯创建一个取值为函数的字典,并经过键值调用函数。你能够在 Go
    里面这么作,可是全部的函数都得接受和返回一样的东西,也就是说,必须具有一样的方法签名

  • 若是你是用 JSON, 并且是混合类型的 JSON,那么你仍是自求多福吧。你得建立一个可以匹配你的 JSON 二进制大对象(blob)格式的个性化结构,而后解组(Unmarshall)原始 JSON 成为你的个性化架构的一个用例。比起在 Python 中的一句“obj = json.loads(json_blob)”要费更多功夫

这么折腾值得吗?

值,一百万个值,超值。速度的提高不容忽视。并且笔者认为这也是促使 Go 成为流行语言的重要缘由。所以在招聘时,笔者认为把 Go 当成 Python 开发者的必备技能也很重要。

原文地址 https://blog.repustate.com/migrating-code-from-python-to-golang-what-you-need-to-know/
本文转自 OneAPM 官方博客

相关文章
相关标签/搜索