协程 / Coroutine


目录

  1. 生产者消费者模型
  2. 从生成器到异步协程– async/await

协程是在一个线程执行过程中可以在一个子程序的预定或者随机位置中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。它本身是一种特殊的子程序或者称作函数。

一个程序可以包含多个协程,可以对比与一个进程包含多个线程。我们知道多个线程相对独立,有自己的上下文,切换受系统控制;而协程也相对独立,有自己的上下文,但是其切换由自己控制,由当前协程切换到其他协程由当前协程来控制。

1 生产者消费者模型

下面以一个例子介绍一个简单的协程实现,

首先,模拟生产者和消费者模型,建立一个消费者函数,接收一个参数为传入的生产者,初始时使用next函数或send(None)来启动,然后连续7次调用send,将程序切入生产者answer,获取结果,最后调用close或send(None)来结束协程。

 import time

 def ask(a):
next(a) # Start generator
# a.send(None)
n = 0
while n < 7: # Ask certain number questions then exit.
print('Ask: Try to ask question %d' % n)
r = a.send(n) # Send Ques number (ask question), receive is r
print('Ask: Received answer <%s>' % r)
n += 1
a.close() # End loop
# try:
# a.send(None)
# except StopIteration as e:
# pass

接下来定义一个生产者answer,生产者会不停返回结果,除非收到None或被调用close函数从而结束。

 def answer():   # Answer generator
ans = '' # First answer for generator start
while True:
qus = yield ans # Return answer
if qus is None:
return
print('Answer: Received question %s' % qus)
time.sleep(1)
ans = 'Best answer' ask(answer())

运行得到结果,

Ask: Try to ask question 0
Answer: Received question 0
Ask: Received answer <Best answer>
Ask: Try to ask question 1
Answer: Received question 1
Ask: Received answer <Best answer>
Ask: Try to ask question 2
Answer: Received question 2
Ask: Received answer <Best answer>
Ask: Try to ask question 3
Answer: Received question 3
Ask: Received answer <Best answer>
Ask: Try to ask question 4
Answer: Received question 4
Ask: Received answer <Best answer>
Ask: Try to ask question 5
Answer: Received question 5
Ask: Received answer <Best answer>
Ask: Try to ask question 6
Answer: Received question 6
Ask: Received answer <Best answer>

可以看到,ask和answer之间完成了协作性任务,同一时间自由一个线程在执行,不存在线程的切换。

2 从生成器到异步协程– async/await

在Python中,生成器和协程总是难以区别,为此,在Python3.5之后,引入了新的关键字async和await,用于将普通的函数或生成器包装成为异步的函数和生成器。

下面用代码展示如何使用生成器和协程完成一个异步操作,

完整代码

 #!/usr/bin/python
# =============================================================
# File Name: gene_to_coro.py
# Author: LI Ke
# Created Time: 1/29/2018 15:34:50
# ============================================================= print('-------- Generator ----------') def switch_1():
print('Switch_1: Start')
yield
print('Switch_1: Stop') def switch_2():
print('Switch_2: Start')
yield
print('Switch_2: Stop') a = switch_1()
b = switch_2()
a.send(None)
b.send(None)
try:
b.send(None)
except StopIteration as e:
re = e.value try:
a.send(None)
except StopIteration as e:
re = e.value print('-------- Async Coro ----------') async def switch_1():
print('Switch_1: Start')
await switch_2()
print('Switch_1: Stop') async def switch_2():
print('Switch_2: Start')
print('Switch_2: Stop') a = switch_1()
try:
a.send(None)
except StopIteration as e:
re = e.value

分段解释

首先利用生成器来完成一个异步操作,定义两个生成器,分别在启动后yield出当前环境,

 print('-------- Generator ----------')

 def switch_1():
print('Switch_1: Start')
yield
print('Switch_1: Stop') def switch_2():
print('Switch_2: Start')
yield
print('Switch_2: Stop')

完成生成器后,首先分别实例化两个生成器,并利用send(None)进行启动,启动a后再启动b,随后再切入b中完成剩余操作,当b完成后捕获StopIteration异常,并再次切入a中完成后续的操作。

 a = switch_1()
b = switch_2()
a.send(None)
b.send(None)
try:
b.send(None)
except StopIteration as e:
re = e.value try:
a.send(None)
except StopIteration as e:
re = e.value

最终运行结果为,

-------- Generator ----------
Switch_1: Start
Switch_2: Start
Switch_2: Stop
Switch_1: Stop

可以看到,利用生成器完成了一个预先设定好的运行流程,仅仅利用单线程完成了一个异步切换的协作式任务。

可是上面的方式存在一个问题,即整个程序的结构十分松散,逻辑上难以理清,因此下面用新增的关键字async和await来完成一个更加符合思维逻辑的异步流程。

首先定义两个异步协程,在协程1中,当协程1开始后,利用await显式地切换至协程2中,当协程2完成后,又继续执行协程1中的操作,整个协程异步的工作顺序在协程内便完成,因此在外部仅需要启动协程1即可。

 print('-------- Async Coro ----------')

 async def switch_1():
print('Switch_1: Start')
await switch_2()
print('Switch_1: Stop') async def switch_2():
print('Switch_2: Start')
print('Switch_2: Stop') a = switch_1()
try:
a.send(None)
except StopIteration as e:
re = e.value

最后得到的结果与前面利用生成器方式得到的结果相同,但却以一种更加清晰的方式完成了异步编程。

-------- Async Coro ----------
Switch_1: Start
Switch_2: Start
Switch_2: Stop
Switch_1: Stop

Python的异步编程[0] -> 协程[0] -> 协程和 async / await的更多相关文章

  1. JavaScript 如何工作的: 事件循环和异步编程的崛起 + 5 个关于如何使用 async/await 编写更好的技巧

    原文地址:How JavaScript works: Event loop and the rise of Async programming + 5 ways to better coding wi ...

  2. 深入理解协程(四):async/await异步爬虫实战

    本文目录: 同步方式爬取博客标题 async/await异步爬取博客标题 本片为深入理解协程系列文章的补充. 你将会在从本文中了解到:async/await如何运用的实际的爬虫中. 案例 从CSDN上 ...

  3. Python的异步编程[0] -> 协程[1] -> 使用协程建立自己的异步非阻塞模型

    使用协程建立自己的异步非阻塞模型 接下来例子中,将使用纯粹的Python编码搭建一个异步模型,相当于自己构建的一个asyncio模块,这也许能对asyncio模块底层实现的理解有更大的帮助.主要参考为 ...

  4. python 之 并发编程(线程Event、协程)

    9.14 线程Event connect线程执行到event.wait()时开始等待,直到check线程执行event.set()后立即继续线程connect from threading impor ...

  5. Python的网络编程[2] -> TFTP 协议[0] -> TFTP 的基本理论

    TFTP 的基本理论 目录 通信流程 数据报文格式 传输终结 异常处理 数据丢失和超时 TFTP(Trivial File Transfer Protocol,简单文件传输协议)是UDP协议族中的一个 ...

  6. python之异步编程

    一.异步编程概述 异步编程是一种并发编程的模式,其关注点是通过调度不同任务之间的执行和等待时间,通过减少处理器的闲置时间来达到减少整个程序的执行时间:异步编程跟同步编程模型最大的不同就是其任务的切换, ...

  7. 深入理解协程(三):async/await实现异步协程

    原创不易,转载请联系作者 深入理解协程分为三部分进行讲解: 协程的引入 yield from实现异步协程 async/await实现异步协程 本篇为深入理解协程系列文章的最后一篇. 从本篇你将了解到: ...

  8. [C#] .NET4.0中使用4.5中的 async/await 功能实现异步

    在.NET Framework 4.5中添加了新的异步操作库,但是在.NET Framework 4.0中却无法使用.这时不免面临着抉择,到底是升级整个解决方案还是不使用呢? 如果你的软件还没发布出去 ...

  9. .NET4.0中使用4.5中的 async/await 功能实现异步

    在.NET Framework 4.5中添加了新的异步操作库,但是在.NET Framework 4.0中却无法使用.这时不免面临着抉择,到底是升级整个解决方案还是不使用呢? 如果你的软件还没发布出去 ...

随机推荐

  1. COGS 497——奶牛派对

    奶牛派对 我们发现每头牛需要走的路程即为它到x的最短路+x到它的最短路. 转化: 于是这道题变成了一道典型的单源最短路问题,只需求出每个点到x的最短路dl,以及从x到此点的最短路d2,然后去找max( ...

  2. 【题解】[USACO12JAN]视频游戏的连击Video Game Combos

    好久没有写博客了,好惭愧啊……虽然这是一道弱题但还是写一下吧. 这道题目的思路应该说是很容易形成:字符串+最大值?自然联想到学过的AC自动机与DP.对于给定的字符串建立出AC自动机,dp状态dp[i] ...

  3. Unescape JavaScript's escape() using C#

    js里面的 unescape escape 对应C#里面 var unescapedString = Microsoft.JScript.GlobalObject.unescape(yourEscap ...

  4. word公式编辑中的转义字符

    Some of the commonly used symbols:      \infty - Infinity      \leq - Less then or equal      \geq - ...

  5. 复杂的json分析

    在复杂的JSON数据的格式中,往往会对JSON数据进行嵌套,这样取值会比之前的取值稍微复杂一点,但是只要思路清晰,其实取法还是一样的.就跟if else语句一样,如果if中套if,if中再套if,写的 ...

  6. MFC 监控界面上所有文本框值的变化

    //控件消息,菜单,按钮等 BOOL CXXDlg::OnCommand(WPARAM wParam, LPARAM lParam) { // TODO: 在此添加专用代码和/或调用基类 int wm ...

  7. 帮助小伙伴写的组装xml字符串类

    import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.uti ...

  8. checkbox和后面文字无法居中对齐的解决方案

    制作前端页面时,表单的页面中都存在表单元素与提示文字无法对齐的问题.下面是针对这一问题的解决方案: 先上结果图看效果,吼吼~ 最上面两个是经过css处理后的效果,已经居中对齐了哦~,最后一个是没有处理 ...

  9. unity下的Line of Sight(LOS)的绘制

    先说说什么是Linf of Sight.在很多RTS游戏中,单位与单位之间的视野关系经常会受到障碍物遮挡.Line of Sight指的就是两个物体之间是否没有障碍物遮挡. 比如在dota中,玩家的视 ...

  10. opencv_人脸检测、模型训练、人脸识别

    人脸检测.模型训练.人脸识别 2018-08-15 今天给大家带来一套人脸识别一个小案例,主要是帮助小伙伴们解决如何入门OpenCV人脸识别的问题,现在的AI行业比较火热,AI技术的使用比较广泛.就拿 ...