Python开发者在转到Go语言之前需要了解什么?
转载请参见文章末尾处的要求。【感谢张佳伟(@ghosert)的热心翻译。如果其他朋友也有不错的原创或译文,可以尝试推荐给伯乐在线。】这是一篇(长)博文, 介绍了我们在 Repustate 迁移大量 Python/Cython 代码到 Go 语言的经验。如果你想了解整个故事,背景和所有的事情,请继续往下读。如果你只是想了解 Python 开发者在一头扎进 Go 语言前需要了解什么,请点击一下链接:从Python迁移到Go的建议(Tips Tricks) 背景在Repustate,我们完成过的最棒的技术成就之一是实现了阿拉伯语的情感分析。阿拉伯语是一块难啃的硬骨头,因为它的词形变化相当复杂。比起譬如英语,阿拉伯语的分词(将一个句子切分呈几个独立的单词)也更困难,因为阿拉伯语的单词本身还可能会包含空白字符(例如:“阿列夫”在一个单词里的位置)。这也谈不上是泄密,Repustate 使用支持向量机(SVM)来获取一个句子背后最有可能的含义,并在其中加上情感元素。 总体上来说,我们使用了 22 种模型(22 个 SVM) 并且在一篇文档中,每一个单词我们都会加以分析。因此如果你有一篇 500 字的文档,那么基于 SVM,会进行十万次的比较。 PythonRepustate 几乎完全就是一个 Python 商店。我们使用 Django 来实现 API 和网站。因此(目前)为了保持代码一致,同时使用 Python 来实现阿拉伯语情感引擎是合情合理的。只是做原型和实现的话,Python 是很好的选择。它的表达能力很强悍,第三方类库等等也很好。如果你就是为了Web服务,Python 很完美。但是当你进行低级别的计算,大量依赖于哈希表(Python 里的字典类型)做比较的时候,一切都变慢了。我们每秒能处理大约两到三个阿拉伯文档,但是这太慢了。比较下来,我们的英语情感引擎每秒能处理大约五百份文档。 瓶颈因此我们开启了 Python 分析器,开始调查是什么地方用了那么长时间。还记得我前面说过我们有 22 个 SVM 并且每个单词都需要经过处理吗?好吧,这些都是线性处理的,非并行处理。所以我们的第一反应是把线性处理改成 map/reduce 那样的操作。简单来说:Python 不太适合用作 map/reduce。当你需要并发的时候,Python 算上好用。在 2013 Python 大会上(译者:PyCon 2013),Guido 谈到了 Tulip,他的这个新项目正在弥补 Python 这方面的不足,不过得过段一段时间才能推出,但是如果已经有了更好用的东西,我们为什么还要等呢? 选Go 语言,还是回家算了?我在Mozilla的朋友告诉我,Mozilla 内部正在将他们大量的基础日志架构切换到 Go 语言上,部分原因是因为强大的 [goroutines]。Go 语言是 Google 的人设计的,并且在设计之初就把支持并发作为第一要务,而不是像 Python 的各种解决方案那样是事后才加上去的。因此我们开始着手把 Python 换成 Go 语言。虽然Go 代码还不算正式上线的产品,但是结果非常令人鼓舞。我们现在能做到每秒处理一千份文档,使用更少的内存,还不用调试你在 Python 里遇到:丑陋的多进程/gevent/“为什么 Control-C 杀不了进程”这些问题。 为什么我们喜欢 Go 语言任何人,对编程语言是如何工作(解释型 vs 编译型, 动态语言 vs 静态语言)有一点理解的话,会说,“切,当然 Go 语言会更快”。是的,我们也可以用 Java 把所有的东西重写一遍,也能看到类似更快的改善,但那不是 Go 语言胜出的原因。你用 Go 写的代码好像就是对的。我搞不清楚到底是怎么回事,但是一旦代码被编译了(编译速度很快),你就会觉得这代码能工作(不只是跑起来不会错,而且甚至逻辑上也是对的)。我知道,这听上去不太靠谱,但是确实如此。这和 Python 在冗余(或非冗余)方面非常类似,它把函数作为第一目标,因此函数编程会很容易想明白。而且当然,go 线程和通道让你的生活更容易,你可以得到静态类型带来的性能大提升,还能更精细的控制内存分配,而你却不必为此在语言表达力上付出太多的代价。 希望能早点知道的事情(Tips Tricks)除去所有这些赞美之词以后,有时你真的需要在处理 Go 代码的时候,相对于 Python,改变一下思维方式。因此这是我在迁移代码时记录的笔记清单 —— 只是在我把 Python 代码转换到 Go 时从我脑子里随机冒出来的点子:没有内建的集合类型(必须使用map,并检查是否存在)因为没有集合,必须自己写交集,并集之类的方法没有tuples 类型,必须写你自己的结构,或者使用 slices (即数组)没有类似 \__getattr__() 的方法,你必须总是检查存在性,而不是设置默认值,例如,在 Python 里,你可以这样写 value = dict.get(“a_key”, “default_value”)必须总是检查错误(或者显式的忽略错误)不能有变量/包没被使用,因此简单的测试也需要有时注掉一些代码在[] byte 和 string 之间转换。 regexp 使用 [] byte (不可变)。这是对的,但是老把一些变量转换来转换去很烦人Python 更宽松。你可以使用超出范围的索引在字符串里取一个片段,而且不会出错。你还可以用负数取出片段,但是 Go 不行你不能混合数据结构类型。也许这样也不太干净,但是有时在 Python 里,我会使用值是混合了字符串和列表的字典。但是 Go 不行,你不得不清理干净你的数据结构或者使用自定义的结构不能解包一个 tuple 或者 list 到几个不同的变量(例如:x, y, z = [1, 2, 3])驼峰式命名风格(如果你没有首字大写方法名/结构名,他们不会被暴露给其它的包)。我更喜欢 Python 的小写字母加下划线命名风格。必须显式检查是否有错误 != nil, 不像在 Python 里,许多类型可以像 bool 那样检查 (0, “”, None 都可以被解释成 “非” 集合)文档在一些模块上太散乱了,例如(crypto/md5),但是 IRC 上的 go-nuts 很好用,提供了巨大的帮助。从数字到字符串的转换(int64 - string) 和 []byte - string (只要使用 string([]byte))不太一样。需要使用 strconv。阅读Go 代码比起 Python 那样写起来如伪代码的语言更像一门编程语言, Go 有更多的非字母数字字符,并且使用 || 和 , 而不是 “or”和“and”写一个文件的话,有 File.Write([]byte) 和 File.WriteString(string), 这点和 Python 开发者的 Python 之道:“解决问题就一种方法 ”相违背。修改字符串很困难,必须经常重排 fmt.Sprintf没有构造函数,因此惯用法是创建 NewType() 方法来返回你要的结构Else (或者 else if)必须正确格式化,else 得和 if 配对的大括号在同一行。奇怪。赋值运算符取决于在函数内还是函数外,例如,= 和 :=如果我只想要“键”或者只想要 “值”,譬如: dict.keys() 或者 dict.values(),或者一个 tuples 的列表,例如:dict.items(),在 Go 语言里没有等价的东西,你只能自己枚举 map 来构造你的列表类型我有时使用一种习惯用法:构造一个值是函数的字典类型,我想通过给定的键值调用这些函数,你在 Go 里可以做到,但是所有的函数必须接受,返回相同的东西,例如:相同的方法签名如果你使用 JSON 并且 你的 JSON 是一个复合类型,恭喜你。 你必须构造自定义的结构匹配 JSON 块里的格式,然后把原始 JSON 解析到你自定义结构的实例中去。比起 Python 世界里 object = json.loads(json_blob) 要做更多的工作 是不是值得?值得,一百万倍的值得。速度的提升太多了,以致很难舍弃。同时,我认为, Go 是目前趋势所在,因此在招新员工的时候,我认为把 Go 当作 Repustate 技术积累的重要一环会很有帮助。]
点军网站制作公司哪家好,找成都创新互联公司!从网页设计、网站建设、微信开发、APP开发、响应式网站建设等网站项目制作,到程序开发,运营维护。成都创新互联公司自2013年创立以来到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选成都创新互联公司。
Go语言int、int64、string之间的转换
import "strconv"
int, err := strconv.Atoi(string)
int64, err := strconv.ParseInt(string, 10, 64)
string := strconv.Itoa(int)
string := strconv.FormatInt(int64,15)
go语言语法(基础语法篇)
import "workname/packetfolder"
导入多个包
方法调用 包名.函数//不是函数或结构体所处文件或文件夹名
packagename.Func()
前面加个点表示省略调用,那么调用该模块里面的函数,可以不用写模块名称了:
当导入一个包时,该包下的文件里所有init()函数都会被执行,然而,有些时候我们并不需要把整个包都导入进来,仅仅是是希望它执行init()函数而已。下划线的作用仅仅是为了调用init()函数,所以无法通过包名来调用包中的其他函数
import _ package
变量声明必须要使用否则会报错。
全局变量运行声明但不使用。
func 函数名 (参数1,参数2,...) (返回值a 类型a, 返回值b 类型b,...)
func 函数名 (参数1,参数2,...) (返回值类型1, 返回值类型2,...)
func (this *结构体名) 函数名(参数 string) (返回值类型1, 返回值类型2){}
使用大小来区分函数可见性
大写是public类型
小写是private类型
func prifunc int{}
func pubfunc int{}
声明静态变量
const value int
定义变量
var value int
声明一般类型、接口和结构体
声明函数
func function () int{}
go里面所有的空值对应如下
通道类型
内建函数 new 用来分配内存,它的第一个参数是一个类型,不是一个值,它的返回值是一个指向新分配类型零值的指针
func new(Type) *Type
[这位博主有非常详细的分析]
Go 语言支持并发,我们只需要通过 go 关键字来开启 goroutine 即可。
goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。
同一个程序中的所有 goroutine 共享同一个地址空间。
语法格式如下:
通道(channel)是用来传递数据的一个数据结构。
通道的声明
通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 - 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。
[这里有比较详细的用例]
go里面的空接口可以指代任何类型(无论是变量还是函数)
声明空接口
go里面的的强制类型转换语法为:
int(data)
如果是接口类型的强制转成其他类型的语法为:
go里面的强制转换是将值复制过去,所以在数据量的时候有比较高的运行代价
Go语言中有单个字符和ascii码值直接转换的方法吗
直接将字符变量赋值给整型变量,即可实现字符到对应ASCII码的转换。
具体实现方法可以参考如下程序段:
char str[]="abds%*34dfs"; // 定义一个字符数组,存放待转换为ASCII码的字符串
int AsciiNum[20]; // 定义一个整型数组,存放字符所对应的ASCII码值,数组大小根据字符串长度进行设置
int i;
// 将字符串的每个字符逐个赋值给整型数组AsciiNum,即实现字符到ASCII码值的转换
for(i=0; istrlen(str); i++)
{
AsciiNum[i] = str[i]; // 最后数组AsciiNum就是字符串每个字符所对应ASCII码值的数组
}
标题名称:转换go语言 go语言类型转换
文章网址:http://lswzjz.com/article/hicjgi.html