上一篇 理解python中的yield关键字 介绍了使用yeld实现生成器函数,这一篇我们来继续深入的了解一下yield,用yield实现协程。

先来解答一下上一篇留下的问题:下面的代码为什么第二次调用next打印None呢?

def 

事实是这样的,yield语句默认返回None。当第一次调用next方法时,生成器函数开始执行,执行到yield表达式为止,但此时赋值操作并为执行。上面的代码中,在第一次调用next的时候,echo生成了1。第二次调用next的时候,yield表达式的值赋给了n,n此时变成None了,再次yield n的时候就自然生成None了。

好了,接下来开始本文的主题。

什么是协程

引用官方的说法:

协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

与线程相比,协程更轻量。一个Python线程大概占用8M内存,而一个协程只占用1KB不到内存。协程更适用于IO密集型的应用。

在讲述协程的实现前,我们有必要先来看一下send方法。

send方法

yield表达式有一个返回值,send方法的作用就是控制这个返回值,send的参数就是yield表达式的返回值。我们来看一下官方文档上关于send的定义

generate.send(value):
生成器的send(value)方法会将value值“发送”给生成器中的方法。value参数变成当前yield表达式的值。send()方法会返回生成器生成的下一个yield值或者StopIteration异常(如果生成器没有生成下一个yield值就退出了)。当通过调用send()启动生成器时,value值必须为None,因为当前还没有yield表达式可以接收参数。

是不是看晕了?我们来看一个例子

def 

上面的代码输出

before yield
after yield: 1
before yield
after yield: 2
before yield
after yield: None
before yield

第一次调用next的时候,程序从函数最开始处运行,打印出

before yield

执行到yield处,停在该处。

接下来,向生成器send(1)。send在这里起到两个作用,一个是将参数值赋给yield的返回值,然后该返回值赋给了变量x;一个是继续程序的执行,直到下一次遇到yield停下来。第二个功能和next类似。其实,next 就相当于 send(None) 。

执行了 send(1) 后,x被赋值给yield的返回值,即send的参数1,并继续往下执行,打印出了

after yield: 1

继续执行,回到循环的开始,向下执行,打印出

before yield

再次遇到yield,停在该处,等待下一次send或next的调用。

向生成器send(2)。这里的步骤和 send(1) 相同,打印出下面两条后,在yield处停住。

after yield: 2

before yield

执行 next(g),x被赋值为yield表达式的返回值,也就是None,继续向下执行,打印出

after yield: None

再次回到循环的开始,向下执行,打印出

before yield

程序运行结束。

现在是不是有点理解send了?

yield和send实现Python协程

我们来用协程实现一个生产者/消费者的例子

import 

运行上面的程序,会输出

[producer] producing 1...
[consumer] consuming 1...
[producer] consumer return: well received
[producer] producing 2...
[consumer] consuming 2...
[producer] consumer return: well received
[producer] producing 3...
[consumer] consuming 3...
[producer] consumer return: well received
[producer] producing 4...
[consumer] consuming 4...
[producer] consumer return: well received
[producer] producing 5...
[consumer] consuming 5...
[producer] consumer return: well received

produce函数负责生产数据,consume函数负责消费数据。具体执行过程如下:

  1. 首先调用consume函数,consume函数的返回是一个生成器,把这个生成器传入produce函数。
  2. produce函数中调用next(c)启动生成器。
  3. 计算 n = n+1 生成数据,一旦生产了数据,调用 c.send(n) 切换到consume执行。
  4. consume函数中拿到数据后赋值给n,继续执行yield后面的语句。
  5. consume函数中打印消费的数据,并设置返回值r,又回到循环的开始,通过yield把结果传回。
  6. produce拿到consume返回的值,继续生产下一个数据。
  7. 5个数据生产完毕后,循环结束,通过c.close()关闭consume,结束全过程。

produce和consume函数在一个线程内执行,通过调用send方法和yield互相切换,实现协程的功能。

c++ 协程_用yield实现协程相关推荐

  1. python yield 协程_用yield实现python协程

    刚刚介绍了pythonyield关键字,趁热打铁,现在来了解一下yield实现协程. 引用官方的说法: 与线程相比,协程更轻量.一个python线程大概占用8M内存,而一个协程只占用1KB不到内存.协 ...

  2. python3 携程_多任务(3):协程

    代码环境:python3.6 上一篇文章我们讲了 python 中多线程的使用:点击阅读,现在我们讲讲 python 中的协程. 异步IO 我们知道,CPU 速度远远快于磁盘.网络等 IO.在 IO ...

  3. pdf 深入理解kotlin协程_深入理解Kotlin协程

    领取成功 您已领取成功! 您可以进入Android/iOS/Kindle平台的多看阅读客户端,刷新个人中心的已购列表,即可下载图书,享受精品阅读时光啦! - | 回复不要太快哦~ 回复内容不能为空哦 ...

  4. (转)python协程2:yield from 从入门到精通

    原文:http://blog.gusibi.com/post/python-coroutine-yield-from/ https://mp.weixin.qq.com/s?__biz=MzAwNjI ...

  5. swoole mysql 协程_关于协程的优点以及swoole 协程的用法

    在上篇文章中php yield关键字以及协程的实现  我们讲到了协程的原理以及运行步骤. 现在我们来继续看下协程的执行顺序. 协程的运行是交叉式运行(串行),只要你发起了一次协程切换,则会立马暂停当前 ...

  6. python中协程与函数的区别_深入浅析python 协程与go协程的区别

    进程.线程和协程 进程的定义: 进程,是计算机中已运行程序的实体.程序本身只是指令.数据及其组织形式的描述,进程才是程序的真正运行实例. 线程的定义: 操作系统能够进行运算调度的最小单位.它被包含在进 ...

  7. c++ 协程_理解Python协程(Coroutine)

    由于GIL的存在,导致Python多线程性能甚至比单线程更糟. GIL: 全局解释器锁(英语:Global Interpreter Lock,缩写GIL),是计算机程序设计语言解释器用于同步线程的一种 ...

  8. 开启协程_「科普」什么是协程?

    阅读本文大概需要 6 分钟 今天要讲的这个东西说实话,我也是今天才知道,一个我们大多数人可能从来都没用过的语法,哪就是传说中的[协程],英文表达是Coroutine. 可能你会说,携程谁不知道啊,不就 ...

  9. python3 协程 写法_理解Python的协程(Coroutine)

    由于GIL的存在,导致Python多线程性能甚至比单线程更糟. GIL: 全局解释器锁(英语:Global Interpreter Lock,缩写GIL),是计算机程序设计语言解释器用于同步线程的一种 ...

最新文章

  1. R语言plotly可视化:plotly可视化在散点图中添加误差条(Scatterplot with Error Bars with plotly in R)
  2. shell实例第23讲:每天定时备份nginx日志
  3. 停止宗教战争,好吗?
  4. PHP第六课 使用方法数组
  5. Linux bond6配置文件,Linux服务器网卡绑定bond配置(示例代码)
  6. 《netty入门与实战》笔记-02:服务端启动流程
  7. Android系统中通过shell命令实现wifi的连接控制
  8. c++ int *p = new int()
  9. 拼装机器人感想_学习制作机器人的感想作文500字15篇
  10. 苏宁易购:全国1071万高考生可免费领取SUPER会员
  11. Oracle case用法
  12. Anndroid 使用相机或相册打开图片
  13. UltraISO 制作U盘启动盘(Ubuntu、CentOS)
  14. win10下 switchhost权限修改问题
  15. 制图利器—MapGIS10.5制图版体验
  16. Java并发编程模拟管程(霍尔Hoare管程、汉森Hansan管程、MESA管程)
  17. 一步一步带你了解Hybrid开发框架之DsBridge
  18. Vim查找、替换与删除常用命令
  19. python实现模仿银行ATM机
  20. 安卓使用javascriptApi快速开发高德地图

热门文章

  1. 计算虚拟化涉及的关键技术有哪几项_都开始商用了 5G的这些关键技术还不知道?...
  2. sql数字转换为字符_Python|图片转换为字符画^_^
  3. Replace Type Code with Subclasses(以子类取代类型码)
  4. 一台微型计算机性能的主要参数及其意义,微型计算机的主要性能指标.ppt
  5. php 商品显示,php – WooCommerce仅显示购买的商品
  6. java正则匹配英文句号_Scala 正则表达式 0411
  7. 软件文档 服务器上,服务器上需要什么软件
  8. 大学计算机成绩统计表怎么做,wps怎么制作成绩表 wps设计成绩统计表的步骤方法...
  9. 外设驱动库开发笔记12:TSEV01CL55红外温度传感器驱动
  10. [数据库]---mysql 插入sql之 INSERT INTO和INSERT IGNORE INTO和REPLACE INTO和ON DUPLICATE KEY UPDATE比较应用