生活中,假设 你是一家制造汽车的老板,员工点击设备的【开始】按钮之后,在设备前需等待30分钟,然后点击【结束】按钮,此时作为老板的你一定希望这个员工在等待的那30分钟的时间去做点其他的工作。

模块asyncio用于编写协程代码,下面利用代码来还原生活中的例子。

定义一个协程

协程(Coroutine),也可以被称为微线程,是一种用户态内的上下文切换技术。简而言之,其实就是通过一个线程实现代码块相互切换执行。
形式为: async def的函数。使用async修饰将普通函数包装成异步函数,直接调用异步函数不会返回结果,而是返回一个协程(coroutine)对象;

# 定义一个协程函数
async def request():print('***')return 123coroutine = request() #调用协程函数函数内部代码不会执行,只是返回一个协程对象
print(coroutine) #<coroutine object request at 0x7fc0a515cdc0>

事件循环

协程对象不能直接运行,需要将协程加入到事件循环loop中。

创建一个事件循环loop

在主线程里,如果没有被设置过任何事件循环,那么调用asyncio.get_event_loop()会创建一个事件循环并返回;
其他线程里需要首先loop=new_event_loop(),然后set_event_loop(loop).

loop = asyncio.get_event_loop() #创建一个事件循环
print('Task:', task)#进入事件循环   Task: <Task pending name='Task-1' coro=<request() running at /Users/demo.py>>

将协程注册到事件循环,并启动事件循环

调用loop.run_until_complete(task)将协程加入到事件循环loop中,并启动事件循环,直到协程(task)执行完成之后终止
在注册事件循环的时候,run_until_complete(task)方法需要一个任务(task)对象,task对象是Future类的子类,保存了协程运行后的状态,用于未来获取协程的结果。

创建一个task

task = asyncio.ensure_future(coroutine) #创建task
print('Task:', task) #Task: <Task pending name='Task-1' coro=<request() running at /Users/demo.py>>loop.run_until_complete(task) #将协程当做任务提交到事件循环的任务列表中,协程执行完成之后终止
print('Task:', task)#关闭事件循环  ***    Task: <Task finished name='Task-1' coro=<request() done, defined at /Users/demo.py>   123

可以通过asyncio.ensure_future(coroutine) 创建task,也可以通过loop.create_task(coroutine)创建task。
asyncio.ensure_future(coroutine):将一个coroutine对象包装成Future对象

**Future对象:**状态:Pending、Running、Done、Cacelled;
创建future的时候,task为pending,
事件循环调用执行的时候当然就是running,
调用完毕自然就是done,
如果需要停止事件循环,中途需要取消,就需要先把task取消,即为cancelled。

绑定回调

在task执行完成的时候可以获取执行的结果,回调函数的最后一个参数是future对象,通过该对象可以获取协程返回值。

def callback(future):print('Status:', future.result()) #获取协程返回值task = asyncio.ensure_future(coroutine) #创建task
print('Task:', task) #Task: <Task pending name='Task-1' coro=<request() running at /Users/demo.py>>
task.add_done_callback(callback) #给task任务绑定回调函数
print('Task:', task) #Task: <Task pending name='Task-1' coro=<request() running at /Users/demo.py:25> cb=[callback() at /Users/demo.py]>loop = asyncio.get_event_loop() #创建一个事件循环
print('Task:', task)#进入事件循环   Task: <Task pending name='Task-1' coro=<request() running at /Users/demo.py>>loop.run_until_complete(task) #将协程当做任务提交到事件循环的任务列表中,协程执行完成之后终止
print('Task:', task)#关闭事件循环
'''***
Status: 123
Task: <Task finished name='Task-1' coro=<request() done, defined at /Users/demo.py>  result=123>
'''print('Task Result:', task.result()) # Task Result: 123

通过task.add_done_callback(callback)方法给task任务添加回调函数,当task(也可以说是coroutine)执行完成的时候,就会调用回调函数。并通过future,result()获取协程执行的结果。
这里我们创建 的task和回调里的future对象实际上是同一个对象。

await

await是一个只能在协程函数中使用的关键字,用于遇到耗时(IO)的操作时事件循环将会挂起 当前协程(任务),去执行其他的协程(任务),直到其他的协程也挂起或者执行完毕,再进行下一个协程的执行。当前协程IO处理完成时,可以再次切换回来执行await之后的代码。

耗时的操作一般是一些IO操作,例如网络请求,文件读取等。协程的目的也是让这些IO操作异步化。

注意: await语法只能出现在通过async修饰的函数中,否则会报SyntaxError错误

这里耗时操作可使用asyncio.sleep函数来模拟IO操作

async def request(x):print("waiting:",x)# 当前协程挂起时,事件循环可以去执行其他协程(任务)。await asyncio.sleep(x)return 123

协程来回切换执行的意义

计算型的操作,利用协程来回切换执行,没有任何意义,来回切换并保存状态 反倒会降低性能。
IO型的操作,利用协程在IO等待时间就去切换执行其他任务,当IO操作结束后再自动回调,那么就会大大节省资源并提供性能,从而实现异步编程(不等待任务结束就可以去执行其他代码)。

协程一般应用在有IO操作的程序中,因为协程可以利用IO等待的时间去执行一些其他的代码,从而提升代码执行效率

结合yield

参考:https://www.cnblogs.com/dhcn/p/9032461.html

import asyncio
all_potatos = [1,2,3,4,5]#当生产者完成和返回之后,这是便能从await挂起的地方继续往下跑,完成消费的过程。而这整一个过程,就是一个异步生成器迭代的流程
async def ask_for_potato():await asyncio.sleep(random.random())all_potatos.extend(Potato.make(random.randint(1, 10)))async def take_potatos(num):count = 0while True:if len(all_potatos) == 0:#当货架上的土豆没有了之后,我可以询问超市请求需要更多的土豆,这时候需要等待一段时间直到生产者完成生产的过程await ask_for_potato()potato = all_potatos.pop()yield potatocount += 1if count == num:breakasync def buy_potatos():bucket = []#async for语法表示我们要后面迭代的是一个异步生成器。async for p in take_potatos(50):bucket.append(p)print('Got potato =',p)if __name__ == '__main__':loop = asyncio.get_event_loop()res = loop.run_until_complete(buy_potatos())loop.close()

参考博客:
https://zhuanlan.zhihu.com/p/137057192

https://www.cnblogs.com/zhaof/p/8490045.html
https://blog.csdn.net/qq_27825451/article/details/86292513
https://zhuanlan.zhihu.com/p/69210021

python中重要的模块asyncio相关推荐

  1. 介绍Python中的__future__模块

    这篇文章主要介绍了介绍Python中的__future__模块,__future__模块使得在Python2.x的版本下能够兼容更多的Python3.x的特性,需要的朋友可以参考下 Python的每个 ...

  2. python中的logging记录日志_[ Python入门教程 ] Python中日志记录模块logging使用实例...

    python中的logging模块用于记录日志.用户可以根据程序实现需要自定义日志输出位置.日志级别以及日志格式. 将日志内容输出到屏幕 一个最简单的logging模块使用样例,直接打印显示日志内容到 ...

  3. python使用教程cmd啥意思-Python 中的cmd模块学习

    Python中的cmd模块类型提供了一个创建命令行解析器的框架.简单的来说,可以继承Cmd来创建命令行界面,然后对所有想处理的命令command执行do_command方法.默认情况下,它使用read ...

  4. python中的绘图模块turtle的使用

    python中的绘图模块turtle的使用(7-20190125) 文章目录: 还是从一个有趣的小应用开始,turtle的骚操作吧 最近小猪配齐比较流行,下面用turtle绘制一个粉红色的小猪猪吧-- ...

  5. linux系统python截图不显示中文_Linux运维知识之解决linux系统下python中的matplotlib模块内的pyplot输出图片不能显示中文的问题...

    本文主要向大家介绍了Linux运维知识之解决linux系统下python中的matplotlib模块内的pyplot输出图片不能显示中文的问题,通过具体的内容向大家展现,希望对大家学习Linux运维知 ...

  6. Python中的random模块

    Python中的random模块用于随机数生成,对几个random模块中的函数进行简单介绍.如下: random.random() 用于生成一个0到1的随机浮点数.如: import random r ...

  7. python中的log模块笔记

    日志相关概念 logging模块简介 使用logging提供的模块级别的函数记录日志 logging模块日志流处理流程 使用logging四大组件记录日志 配置logging的几种方式 向日志输出中添 ...

  8. python中的系统模块_python中一些获取系统信息的模块

    1.platform模块 python中,platform模块给我们提供了很多方法去获取操作系统的信息 如: import platform platform.platform() #获取操作系统名称 ...

  9. 深入理解python中的select模块

    简介 Python中的select模块专注于I/O多路复用,提供了select poll epoll三个方法(其中后两个在Linux中可用,windows仅支持select),另外也提供了kqueue ...

最新文章

  1. 苹果过审ipv6问题
  2. 借助Apache Hadoop大规模扩展Apache Solr实时实时索引
  3. spark rdd读取文件
  4. [洛谷P5367]【模板】康托展开
  5. OpenLayers学习入门篇
  6. 纯干货:LCD屏和OLED屏的区别?手机屏幕材质各有什么区别?
  7. 【数学建模】数学建模学习2---整数规划(例题+matlab代码实现)
  8. linux修改只读文件指令,linux修改文件权限
  9. 从电子印章到印控一体化,企业印章管理更安全高效
  10. JavaScript对象 1
  11. 帝国cms登陆表单的制作与变量说明
  12. 椭圆曲线密码算术(ECC)原理
  13. Mybatis---主键回填 (*^▽^*)
  14. 2023最火批量getshell工具
  15. 巩膜分割论文:ScleraSegNet: an Improved U-Net Model with Attention for Accurate Sclera Segmentation
  16. C++ rand() 随机函数的用法
  17. numpy 计算最大回撤
  18. R语言多项式线性模型:最大似然估计二次曲线
  19. matlab在高等数学中的,matlab在高等数学中的应用
  20. 【愚公系列】2023年01月 Java教学课程 017-Random随机数的使用

热门文章

  1. linux桌面文件夹改图标,Linux 给桌面程序设置个性化图标
  2. python和java对比并发_Python并发编程之从性能角度来初探并发编程(一)
  3. 序列化和反序列化--转
  4. 使用MAT(Memory Analyzer Tool)工具分析dump文件--转
  5. gcc动态链接库基本知识
  6. 若依JAVA开源框架自动生成代码步骤记录-创建子module以及导入子module相关问题
  7. Web3.0来了!玩法变了
  8. 2019区块链行业指南
  9. 拼多多提交赴美上市招股书 陆奇担任独立董事兼薪酬委员会主席
  10. Star: Ubuntu下配置和编译cpp-ethereum客户端启动GPU加速交易