简介

因为最近一段时间需要研究一些openstack相关的东西,在阅读一些相关代码的时候碰到很多python特定的一些特性,比如generator, coroutine以及一些相关的类库,比如eventlet, greenlet。在openstack里引用的第三方类库非常多,这些特性和类库看起来还比较复杂。如果需要对openstack里面某些特性的实现非常熟悉的话,就需要对这些牵涉到的基础的东西有个很好的了解。这里就针对coroutine的特性和它的使用做一个总结。

coroutine的定义和使用

在前面一篇关于generator的文章里,我提到了怎么定义和使用generator。当时我们使用yield value或者和list comprehension类似的语法来定义generator。我们返回的generator其实是一个可以不断取得数据的集合,所以一般使用它们的代码一般是一个循环。在这种情况下,我们感觉像是首先定义了一组管道,然后在真正需要的时候才在代码里去提取它们。

实际上,coroutine和generator还是很有关系的,我们来看如下的代码:

def grep(pattern):

print "Looking for %s" % pattern

while True:

line = (yield)

if pattern in line:

print line,

这部分代码看起来和generator很像,不过又不同。这里有一个line = (yield) 的语句。而在generator里,我们是需要yield value来返回值的。而这里后面根据获得的值还可以打印出来了。我们使用它们的代码如下:

if __name__ == '__main__':

g = grep("python")

g.next()

g.send("Yeah, but no, but yeah, but no")

g.send("A series of tubes")

g.send("python generators rock!")

这里,我们定义了方法grep,然后调用一个send方法。代码执行的输出结果如下:

Looking for python

python generators rock!

结合前面代码的部分,看起来好像是yield部分后面会针对包含有python这个串的字符进行处理。而没有的则不会处理。看来这个yield像是有什么玄机,看起来不简单。

实际上,我们在使用line = (yield)这部分就是定义了一个coroutine。coroutine是什么呢?coroutine可以说是一种实现协作式编程的手法。它可以设置有多个入口点和恢复执行的点,可以实现一些执行流程的转移。这部分概念看起来有点难懂。我们以前面的这部分代码为例来分析一下想关的概念。

在我们代码中,定义的yield这个部分相当于等待接收数据。所以在没有数据到来的时候,它就相当于被阻塞,等在那里。而为了触发这个部分,我们在使用的代码里首先用g.next()来初始化它。然后通过g.send("")方法将数据发送给它。这样,yield返回的就是send方法里带的参数了。然后我们可以接着在循环部分来处理它。这样看来,coroutine更多的是一个数据消费者的角色。每次都是等数据过来,来了之后就通过yield部分返回,然后处理。否则就等在那里。

coroutine的几个应用

因为coroutine相当于一个数据的消费者,我们可以做一种这样的应用。首先是一个生产者将一些数据准备好,然后将数据发送给一个coroutine来处理。我们来看一个文件处理的示例:

import time

def follow(thefile, target):

thefile.seek(0,2) # Go to the end of the file

while True:

line = thefile.readline()

if not line:

time.sleep(0.1) # Sleep briefly

continue

target.send(line)

这里是一个读取文件,然后将文件内容通过target发送到target来处理的过程。所以我们这里要做的就是将target作为一个参数传入给follow方法。当然,target在这里必须是一个coroutine,它来接收和处理这些数据。target的定义如下:

@coroutine

def printer():

while True:

line = (yield)

print line,

这里用到了yield,然后就可以直接将接收到的数据打印出来了。当然,还有一个值得注意的地方是用到了一个@coroutine的decorator。因为在每次使用coroutine之前我们需要调用一次target.next()或者target.send(None)来初始化它。这样我们使用的时候很容易忘记这一步,一种办法就是定义好一个这样的decorator,然后每次将这个decorator加上就保证这一步被执行了。@coroutine decorator的定义如下:

def coroutine(func):

def start(*args,**kwargs):

cr = func(*args,**kwargs)

cr.next()

return cr

return start

对于这部分decorator理解如果有问题的话可以参考我decorator相关的这篇文章。我们最终使用前面这部分的代码如下:

if __name__ == '__main__':

f = open("access-log")

follow(f,printer())

当然,这个示例主要讲的是使用一个coroutine来处理一个传递过来的消息。如果我们要构造类似于pipeline的东西,可以将一个coroutine同时当作数据处理的部分,也可以当作数据传递的部分,比如看如下的代码:

@coroutine

def grep(pattern,target):

while True:

line = (yield) # Receive a line

if pattern in line:

target.send(line) # Send to next stage

这里我们定义的grep方法在接收到数据之后,相当于做了一个判断,如果pattern在传入的line中间,则将这个数据传递给下一个coroutine处理。这就实现了一个pipeline的雏形。当然,除了这种传输的示例,我们也可以将消息传递给多个coroutine。这些示例我们可以参考后面的一些资料去做详细的分析。

关于控制传递

在wiki上关于coroutine的介绍,引用了经典的producer-consumer问题。以前针对这个问题,更多的是针对多线程的producer-consumer问题处理。在那种场景下,我们需要通过锁或者某些互斥变量来实现对队列元素的处理。而实际上,用coroutine来解决这个问题也是一种很理想的方法。在wiki上给出的伪代码是这样的:

coroutine produce

loop

while q is not full

create some new items

add the items to q

yield to consume

coroutine consume

loop

while q is not empty

remove some items from q

use the items

yield to produce

这些代码里最有意思的地方就是,我们完全可以用python coroutine的方式来做一个实现。比如说,我们可以将queue里元素的个数作为传递的参数。作为consumer,可以采用这样的方式来写:

@coroutine

def consumer(target):

while True:

items = (yield)

if items > 0:

remove item from queue

items -= 1

target.send(items)

作为producer也可以采用类似的方法来写。这里就不再赘述了。当然,还有一个要注意的地方就是,这里虽然实现了控制的转移,但是并没有牵涉到线程的变换,这里所有的一切其实还是在同一个进程里执行的。只不过这种控制转移的方式在很多地方有比较高效率的应用,它在实现事件循环和分发、非阻塞IO访问方面有很多的应用。我也会在后续的一些文章里针对它们的一些应用做进一步的分析。

总结

coroutine是一个实现多个任务之间互相切换的手段,它相当于一种将一个当前执行的结果传递给另外一个过程。和generator的使用过程比起来,它更像是一种“推”模式。因为我们要使用一个coroutine的时候,必然是需要有其它的过程send数据过来。因为yield的过程有点类似于一个操作系统里中断的概念,它相当于将一个进程的当前执行过程暂停,然后跳转到另外一个过程。这种过程和我们传统通过栈实现的子过程调用很不一样,所以表面上理解起来还是有点困难。

参考材料

http://en.wikipedia.org/wiki/Coroutine

http://www.dabeaz.com/coroutines/

python coroutine_python coroutine的学习和总结相关推荐

  1. python coroutine_python coroutine的学习跟总结[转]

    简介 因为最近一段时间需要研究一些openstack相关的东西,在阅读一些相关代码的时候碰到很多python特定的一些特性,比如generator, coroutine以及一些相关的类库,比如even ...

  2. python coroutine_Python coroutine的坑

    目前有个后端worker用的python 2.7写的,一次起10个gen.coroutine来跑黑盒的代码,这些代码很多是在做HTTP request. 在server端发现这些来自worker的la ...

  3. python coroutine_python coroutine

    python coroutine 前言 OOAD课程是用python教的,其中涉及到大量的python语法糖,老师也算是手把手教如何写出OO的python,但一个学期没听课只能期末补一补. Corou ...

  4. python值得报班学习吗

    python值得报班学习吗?最近有很多想要学习Python的同学都会问到这个问题,Python在近几年的发展前景是非常不错的,想要学会Python编程语言,建议还是报班学习,来看看下面的详细介绍吧. ...

  5. 赠书 | 干货!用 Python 动手学强化学习

    01 了解强化学习 新闻报道中很少将强化学 习与机器学习.深度学习.人工智能这些关键词区分开来,所以我们要先介绍什么是强化学习,再讲解其基本机制. 强化学习与机器学习.人工智能这些关键词之间的关系: ...

  6. python使用Spacy迁移学习库进行句法分析实战

    python使用Spacy迁移学习库进行句法分析实战 目录 使用Spacy迁移学习库进行句法分析实战 Spacy

  7. 如何用 Python 进行基于深度学习的计算机视觉项目开发?

    令人惊喜的"智能"年代 深度学习有着广阔的前景 我们正处在一个"智能"的年代,比如智能手机中的语音助手.机器翻译和人脸识别:战胜过日本将棋冠军.国际象棋冠军, ...

  8. 风变编程python第一关脸黑怪我喽_风变编程:Python适合编程初学者学习吗?

    来源标题:风变编程:Python适合编程初学者学习吗? 据百度大数据统计每月有4260705的用户在百度检索Python相关介绍,在大众周围,也总是充斥着各种如何学习Python的声音,许多人已经对于 ...

  9. 自学python困难吗_Python学习难不难?零基础好学吗?

    Python学习难不难?零基础好学吗?我想对于很多人来说,这都是非常关键的问题,也是很多人都在疑惑的问题.现在市场发展,行业的竞争压力是非常大的,转型的人也是非常多,对于不少人转型人才来说,Pytho ...

最新文章

  1. 报名 | 期末考后,快来打比赛赢万元奖金!(北京上海)
  2. 2014百度研发真题及其解析-求比指定数大且最小的“不重复数”
  3. 【学习】009 NIO编程
  4. Apache中的Order Allow,Deny用法详解
  5. Git rebase命令实战
  6. 使用PostgREST构建PostgreSQL数据库的REST风格API
  7. PhotoSwipe源码解读系列(二)
  8. DEDECMS 另类***
  9. python安装numpy库出错_numpy安装失败-小失误
  10. myeclipse+JDK10+tomcat9 配置
  11. wallhaven壁纸下载
  12. 计算机英语领域有哪些构词法,计算机专业英语的构词方法(共2969字).doc
  13. 最简单的python语言实现汉诺塔游戏
  14. Windows 上安装 Bugzilla 详解
  15. 25万英汉词典汉英词典ACCESS\SQLite3数据库
  16. RIV A128显卡维修
  17. backupexec mysql_backup-mysql.sh
  18. 国产操作系统之凝思磐石安装
  19. C语言 利用高斯消元求解方程组
  20. 994. 腐烂的橘子(Leetcode)(多源BFS)

热门文章

  1. 经验分享:iOS平台UI设计规范
  2. 【量化系列】使用聚宽实现净利润跳空策略
  3. Linux配置ntp时间服务器(全)
  4. HP XP7 GAD双活实现的理解
  5. cmdline -[command line,__fdt_pointer,initial_boot_params] boot_command_line 获取
  6. 安卓Android Studio布局文件分类存放,java文件分类存放
  7. win10解决打开QQ“initiation failure 0x000000c
  8. 第七讲:7.物联网土壤湿度远程监控+自动花浇水
  9. 如何修改sublime3注释的颜色
  10. C.1 百度飞桨:ERNIE 3.0 、通用信息抽取 UIE、paddleNLP的安装使用[一]