Python的异步编程[0] -> 协程[0] -> 协程和 async / await
协程 / Coroutine
目录
协程是在一个线程执行过程中可以在一个子程序的预定或者随机位置中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。它本身是一种特殊的子程序或者称作函数。
一个程序可以包含多个协程,可以对比与一个进程包含多个线程。我们知道多个线程相对独立,有自己的上下文,切换受系统控制;而协程也相对独立,有自己的上下文,但是其切换由自己控制,由当前协程切换到其他协程由当前协程来控制。
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的更多相关文章
- JavaScript 如何工作的: 事件循环和异步编程的崛起 + 5 个关于如何使用 async/await 编写更好的技巧
原文地址:How JavaScript works: Event loop and the rise of Async programming + 5 ways to better coding wi ...
- 深入理解协程(四):async/await异步爬虫实战
本文目录: 同步方式爬取博客标题 async/await异步爬取博客标题 本片为深入理解协程系列文章的补充. 你将会在从本文中了解到:async/await如何运用的实际的爬虫中. 案例 从CSDN上 ...
- Python的异步编程[0] -> 协程[1] -> 使用协程建立自己的异步非阻塞模型
使用协程建立自己的异步非阻塞模型 接下来例子中,将使用纯粹的Python编码搭建一个异步模型,相当于自己构建的一个asyncio模块,这也许能对asyncio模块底层实现的理解有更大的帮助.主要参考为 ...
- python 之 并发编程(线程Event、协程)
9.14 线程Event connect线程执行到event.wait()时开始等待,直到check线程执行event.set()后立即继续线程connect from threading impor ...
- Python的网络编程[2] -> TFTP 协议[0] -> TFTP 的基本理论
TFTP 的基本理论 目录 通信流程 数据报文格式 传输终结 异常处理 数据丢失和超时 TFTP(Trivial File Transfer Protocol,简单文件传输协议)是UDP协议族中的一个 ...
- python之异步编程
一.异步编程概述 异步编程是一种并发编程的模式,其关注点是通过调度不同任务之间的执行和等待时间,通过减少处理器的闲置时间来达到减少整个程序的执行时间:异步编程跟同步编程模型最大的不同就是其任务的切换, ...
- 深入理解协程(三):async/await实现异步协程
原创不易,转载请联系作者 深入理解协程分为三部分进行讲解: 协程的引入 yield from实现异步协程 async/await实现异步协程 本篇为深入理解协程系列文章的最后一篇. 从本篇你将了解到: ...
- [C#] .NET4.0中使用4.5中的 async/await 功能实现异步
在.NET Framework 4.5中添加了新的异步操作库,但是在.NET Framework 4.0中却无法使用.这时不免面临着抉择,到底是升级整个解决方案还是不使用呢? 如果你的软件还没发布出去 ...
- .NET4.0中使用4.5中的 async/await 功能实现异步
在.NET Framework 4.5中添加了新的异步操作库,但是在.NET Framework 4.0中却无法使用.这时不免面临着抉择,到底是升级整个解决方案还是不使用呢? 如果你的软件还没发布出去 ...
随机推荐
- JSON教程(1)
JSON:JavaScript对象表示发即JavaScript Object Notation. JSON是存储和交换文本信息的语法.类似XML. JSON比XML更小,更快,更易解析. { &quo ...
- HTML5<canvas>标签:使用canvas元素在网页上绘制线条和圆(1)
什么是 Canvas? HTML5 的 canvas 元素使用 JavaScript 在网页上绘制图像. 画布是一个矩形区域,您可以控制其每一像素. canvas 拥有多种绘制路径.矩形.圆形.字符以 ...
- 【BZOJ 1770 】 [Usaco2009 Nov]lights 燈 dfs+异或方程组
这道题明显是异或方程组,然而解不一定唯一他要的是众多解中解为1的数的最小值,这个时候我们就需要dfs了我们dfs的时候就是枚举其有不确定解的数上选0或1从而推知其他解,由于我们dfs的时候先0后1,虽 ...
- Eclipse来push,fetch,rebase代码
如何与项目里的其他人一起合作项目,提交代码并更新呢?这里提出我比最近用到的两种工具:一种是Eclipse,另外一个是SourceTree.个人推荐从事Java开发的话,可以用Eclipse.当然,还有 ...
- centos7上安装docker-ce社区版
报错:Error: docker-ce-selinux conflicts with 2:container-selinux-2.12-2.gite7096ce.el7.noarch 转载:http: ...
- HTTP协议中的ContenType类型大全(转)
".*"="application/octet-stream"".001"="application/x-001"&qu ...
- 排序(bzoj 4552)
Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这 ...
- jQuery操纵DOM
一.基本操作 1.html() - 类似于原生DOM的innerHTML属性 *获取 - html(); *设置 - html("html代码"); 2.val() - 类似于原生 ...
- 【BZOJ2330】【SCOI2011】糖果 [差分约束]
2330: [SCOI2011]糖果 Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description 幼儿园 ...
- Chrome浏览器跨域插件
Moesif Origin & CORS Changer 这个插件允许发送跨域请求,重写Request Origin 和 CORS headers. 解决Debug Javascript时候出 ...