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

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

背景

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

Python

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

瓶颈

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

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

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

虽然 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 开发者的必备技能也很重要。

OneAPM 能帮你查看 Python 应用程序的方方面面,不仅能够监控终端的用户体验://blog.oneapm.com/tags-%E7%94%A8%E6%88%B7%E4%BD%93%E9%AA%8C.html,还能监控服务器性能,同时还支持追踪数据库、第三方 API 和 Web 服务器的各种问题。想阅读更多技术文章,请访问 OneAPM 官方技术博客

本文转自 OneAPM 官方博客

原文地址: https://blog.repustate.com/migrating-code-from-python-to-golang-what-you-need-to-know/

Python 开发者在迁移到 Go(lang) 时需要知道哪些事?的更多相关文章

  1. Python开发者须知 —— Bottle框架常见的几个坑

    Bottle是一个小巧实用的python框架,整个框架只有一个几十K的文件,但却包含了路径映射.模板.简单的数据库访问等web框架组件,而且语法简单,部署方便,很受python开发者的青睐.Pytho ...

  2. Python开发者最常犯的10个错误

    Python是一门简单易学的编程语言,语法简洁而清晰,并且拥有丰富和强大的类库.与其它大多数程序设计语言使用大括号不一样 ,它使用缩进来定义语句块. 在平时的工作中,Python开发者很容易犯一些小错 ...

  3. 强大的jupyter,python开发者的福音

    jupyter是一种交互式计算和开发环境的笔记,ipython命令行比原生的python命令行更加友好和高效,还可以运行web版的界面,支持多语言,输出图形.音频.视频等功能. 一.安装 pip3 i ...

  4. Python开发者年度调研,结果出乎意料!

    来源商业新知网,原标题:Python开发者年度调研:一半Python用户也用JS,2/3选择Linux系统 作为高级编程语言,Python的受欢迎程度近几年一直在往 上涨.每年,Python官方都会针 ...

  5. Python 开发者的 6 个必备库,你都了解吗?

    无论你是正在使用 Python 进行快速开发,还是在为 Python 桌面应用制作原生 UI ,或者是在优化现有的 Python 代码,以下这些 Python 项目都是应该使用的. Python那些事 ...

  6. Python 开发者节省时间的 10 个小技巧

    Python 是一个美丽的语言,可以激发用户对它的爱.所以如果你试图加入程序员行列,或者你有点厌倦C++,Perl,Java 和其他语言,我推荐你尝试Python. Python有很多吸引程序员的功能 ...

  7. 2018 Python开发者大调查:Python和JavaScript最配?

    在2018年秋季,Python软件基金会与JetBrains发起了年度Python开发者调查. 报告的目的是寻找Python领域的新趋势,帮助开发者深入了解2018年Python开发者的现状. 该报告 ...

  8. 将Android手机打造成你的Python开发者桌面#华为云·寻找黑马程序员#

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动",获取华 ...

  9. 2016 年 Python 开发者调查结果

    1.在团队中工作 vs 独立工作 有趣的是,半数的受访者大部分时间在团队中工作,而另外半数的受访者则独立的做项目. 在公司中工作 vs 独立从事自己的项目 大约80%的受访者告诉我们,他们在公司里面工 ...

随机推荐

  1. 【从0到1学jQuery】jQuery中each()和$.each()的使用

    引子: 最近遇到一个问题,就是在each()函数中怎么模拟for循环中的break和continue的操作.所以就查看了jQuery关于这个函数的文档,并且总结一下. 演示代码如下: <div& ...

  2. bower 和 npm 的区别

    前端技术和工程实践真的是突飞猛进啊,想当年,我这个半业余前端吭哧吭哧做页面的时候,哪有这么多东西可以用啊,现在先进到我都完全看不懂了.本文主要讲一下同是包管理器的bower和npm的差别. 主要也是在 ...

  3. [Python 从入门到放弃] 6. 文件与异常(二)

    本章所用test.txt文件可以在( [Python 从入门到放弃] 6. 文件与异常(一))找到并自行创建 现在有个需求,对test.txt中的文本内容进行修改: (1)将期间的‘:’改为‘ sai ...

  4. logstash-1-安装配置

    centos logstash logstash logstash是什么呢, 他是一个数据管道, JRuby编写的运行在java虚拟机的具有收集, 分析和转发数据流功能的工具 特性: 安装 1), w ...

  5. c# LINQ用法

    一.什么是LINQ LINQ(读音link)代表语言集成查询(Language Integrated Query),是.NEt框架的扩展,它允许我们用SQL查询数据库的方式来查询数据的集合,使用它,你 ...

  6. [转]腾讯云Linux云服务器文件上传利器——WinSCP

    本文转自:http://bbs.qcloud.com/thread-4379-1-1.html WinSCP简介 WinSCP是一个Windows环境下使用SSH的开源图形化SFTP客户端.同时支持S ...

  7. 控制器中获取Field值

    在ASP.NET MVC程序中,我们需要POST Data到制器中,是有很多方法.但是我们想在控制器中,获取Feild值呢?怎样获取?你可以留意到有一个类FormCollection.它能帮助到我们解 ...

  8. Js的substring和C#的Substring

    Js的substring 语法: 程序代码String.substring(start, end) 说明:返回一个从start开始到end(不包含end)的子字符串. 示例: 程序代码var str= ...

  9. 24.Linux-Nand Flash驱动(分析MTD层并制作NAND驱动)

    1.本节使用的nand flash型号为K9F2G08U0M,它的命令如下: 1.1我们以上图的read id(读ID)为例,它的时序图如下: 首先需要使能CE片选 1)使能CLE 2)发送0X90命 ...

  10. 记录怎样把安全证书导入到java中的cacerts证书库

    这次项目上需要去证书中解析公钥所以这里分享下方法: 首先准备一个证书文件比如叫:test.crt(一般是cer结尾) 下一步准备把证书导入到导入java中的cacerts证书库里 方法如下: 比如本地 ...