Python的generator和Go的goroutine是常用的技术。没看到有人分析过关系,记录一下。这两个概念都是为了方便在生产者-消费者模式下编程而发明的。Python的生成器与迭代器和可迭代对象在同一行。Go出现的时间晚于Python,也是为了解决同样的编程方便的问题,使用了channel和goroutine两个概念。Go的做法Go的做法比较容易理解,因为和课本上的概念一致:producer和consumer各自是一个goroutine,一个goroutine是一个greenthread——放弃自己执行,让其他gorotine有机会占用CPU而不是依靠抢占机制(如OS内核)强制当前线程休眠,从而为其他线程腾出CPU。生产者将数据写入通道,消费者从通道中读取数据。通道是一个阻塞队列,它可以有一个缓冲区。读取可以通过循环语法完成。例如packagemainfuncproducer(nint)chanint{ch:=make(chanint)gofunc(){//Thisgoroutineistheproducerfori:=0;iIterator[int]:foriinrange(n):yieldiforiinproducer(5):print(i)与Python相比,producer不是函数,因为没有返回其中,而是一个发电机。因为里面有收益。函数返回一个值。生成器返回一个迭代器。Go的生产者是一个返回通道的函数。Go中没有生成器这样的“新概念”。上述Python生成器中的代码与Go生产者中启动goroutine的代码几乎一模一样,只是ch<-i被yieldi代替了。那么Python生成器返回的迭代器是什么呢?其实就是Go通道,或者说阻塞队列。从这个角度来看,Python生成器又是一个函数,返回一个阻塞队列。Python中最常用的生成器是范围——它也出现在上面的例子中。所以在上面的例子中,当调用range时,已经创建了一个Python线程来将数字写入到range返回的阻塞队列中。producer只是从这个queue中取出数,然后yield给producer创建的第二个queue,让producer(5)中fori这一行(主线程执行)读取。这样一系列的三个Python线程,由两个队列串联连接,是RobPike在著名幻灯片https://talks.golang.org/2012/concurrency.slide#1中展示的Go并发模式中的管道:但是这里有一个区别,如果我们的计算机中有多个CPU内核,则goroutines可以并行执行。然而,Python线程虽然是OS线程,但它们受制于Python的GIL,所以任何时候都只有一个Python在执行,即使我们有很多CPU内核。请看https://www.zhihu.com/pin/1343421894465474560Occam'sRazor当我们设计一个系统时,我们往往需要遵循一个哲学原则Occam'sRazor——我们在各种手段中选择最简单的一种来达到目标??。这也是该列名称的由来。在汉语中,这个原理(哲学原理)被称为“去繁琐简三秋”。如果做不到,难免会积累未完成的技术债,以至于无法“以不同的标准来接收新的二月花”。对比上面两个Go和Python的例子,很明显Python例子的代码更简单。那么是不是说Python语言的设计比Go更符合奥卡姆剃刀的原则呢?恐怕不完全是。Python代码虽然简短,但需要使用者理解更多的概念(生成器、迭代器,以及它们与函数、队列的潜在关系)——这也是一种开销。这只是一个提醒,要专注于保持设计简单。不是挖坑对比Python和Go。如果回复涉及此类比较,请删除。:-)