asyncio模块实现单线程-多任务的异步协程
本篇介绍基于asyncio模块,实现单线程-多任务的异步协程
基本概念
协程函数
- 协程函数: 定义形式为
async def的函数;
aysnc
在
Python3.5+版本新增了aysnc和await关键字,这两个语法糖让我们非常方便地定义和使用协程。如果一个函数的定义被
async修饰后,则该函数就是一个特殊的函数(协程函数)。
1 |
# 使用 async 关键字修饰函数后,调用该函数,但不会执行函数,而是返回一个coroutine协程对象 |
运行分析:
直接调用这个函数的话并不会被执行,也会出现一条警告
RuntimeWarning: coroutine 'get_request' was never awaited。对于它的解释 官方文档 里提到,当协程程序被调用而不是被等待时(即执行
get_request('www.b.com')而不是await get_request('www.b.com'))或者协程没有通过asyncio.create_task()被排入计划日程(创建任务对象),asyncio 将会发出一条RuntimeWarning。当然 asyncio.create_task( get_request) 是py3.7中的,在之前的版本中是用到的 asyncio.ensure_future( get_request )
await
- 在协程中如果要调用另一个协程就使用
await。要注意await关键字要在async定义的函数中使用,而反过来async函数可以不出现await - 如果一个对象可以在
await语句中使用,那么它就是 可等待 对象。许多 asyncio API 都被设计为接受可等待对象。 - 可等待 对象有三种主要类型: 协程, 任务 和 Future.
- 通过
ensure_future或create_task函数打包协程对象即可得到任务。 Future是一种特殊的 低层级 可等待对象,表示一个异步操作的 最终结果。- 不用回调方法编写异步代码后,为了获取异步调用的结果,引入一个 Future 未来对象。Future 封装了与 loop 的交互行为,add_done_callback 方法向 epoll 注册回调函数,当 result 属性得到返回值后,会运行之前注册的回调函数,向上传递给 coroutine。
- 通常情况下 没有必要 在应用层级的代码中创建 Future 对象
- 通过
1 |
import asyncio async def producer(): |
asyncio.run()函数用来运行最高层级的入口点 “main()” 函数,更多解释详见 官方文档此函数总是会创建一个新的事件循环并在结束时关闭之。它应当被用作 asyncio 程序的主入口点,理想情况下应当只被调用一次。
协程对象
协程对象*:调用 *协程函数 所返回的对象。
- 特殊函数被调用后,函数内部的实现语句不会被立即执行,然后该函数调用会返回一个协程对象。
结论:协程对象 == 特殊的函数调用
1 |
async def get_request(url): |
任务对象
- 任务对象其实就是对协程对象的进一步封装。
- 任务 被用来设置日程以便 并发 执行协程。
结论:任务对象 == 高级的协程对象 == 特殊的函数调用
特性:可以绑定回调(爬虫中回调函数常用来做数据解析)
1 |
import asyncio |
绑定回调
回调函数什么时候被执行?
- 任务对象执行结束后执行
task.add_done_callback(func)
- func必须要有一个参数,该参数表示的是该回调函数对应的任务对象
回调函数的参数.result(): 任务对象对应的特殊函数执行结束的返回值。
事件循环对象
- 作用:将其内部注册的任务对象进行异步执行。
- 事件循环是异步编程的底层基石。
- 在py3.6中我们需要手动创建事件循环对象。
- 在py3.7中,有了高层级的 asyncio 函数,例如 asyncio.run(),就很少有必要使用 低层级函数 来手动创建和关闭事件循环。
1 |
import asyncio |
- 与py3.6相比,都是先做一个任务列表,然后py3.6需要手动创建事件循环对象
get_event_loop并使用run_until_complete来达到异步执行,而在py3.7中,gather会并发的执行传入的可等待对象并在run的调用下完成异步执行。所以在新版py3.7中,我们无需手动创建和关闭事件循环了。 - py3.7用 create_task 代替 ensure_future。
编码流程
定义协程函数
创建协程对象
封装任务对象
- 绑定回调函数
创建事件循环对象
将任务对象注册到事件循环对象中,并且开启事件循环。
按照流程完整的py3.6代码如下:
1 |
import asyncio |
note:在特殊函数内部的实现语句中不可以出现不支持异步的模块对应的代码,否则就会终止多任务异步协程的异步效果。
在py3.7中,则为
定义协程函数
定义 asyncio 程序的主入口
- 创建协程对象
- 封装任务对象
- 绑定回调函数
asyncio.run(main())
按照流程完整的py3.7代码如下:
1 |
import asyncio |
异步的本质
按照注册顺序执行,遇到阻塞就会挂起,执行下一个任务。
当上一个任务的阻塞结束后,就会继续执行该任务。
真正的挂起是由
asyncio.wait(tasks)做到的

图片来自: 谈谈Python协程技术的演进

图片来自 理解 Python asyncio
底层还没有理解,先把大佬的图粘过来慢慢研究
asyncio模块实现单线程-多任务的异步协程的更多相关文章
- python爬虫---单线程+多任务的异步协程,selenium爬虫模块的使用
python爬虫---单线程+多任务的异步协程,selenium爬虫模块的使用 一丶单线程+多任务的异步协程 特殊函数 # 如果一个函数的定义被async修饰后,则该函数就是一个特殊的函数 async ...
- 爬虫必知必会(4)_异步协程-selenium_模拟登陆
一.单线程+多任务异步协程(推荐) 协程:对象.可以把协程当做是一个特殊的函数.如果一个函数的定义被async关键字所修饰.该特殊的函数被调用后函数内部的程序语句不会被立即执行,而是会返回一个协程对象 ...
- 小爬爬4.协程基本用法&&多任务异步协程爬虫示例(大数据量)
1.测试学习 (2)单线程: from time import sleep import time def request(url): print('正在请求:',url) sleep() print ...
- python爬虫--多任务异步协程, 快点,在快点......
多任务异步协程asyncio 特殊函数: - 就是async关键字修饰的一个函数的定义 - 特殊之处: - 特殊函数被调用后会返回一个协程对象 - 特殊函数调用后内部的程序语句没有被立即执行 - 协程 ...
- 消息/事件, 同步/异步/协程, 并发/并行 协程与状态机 ——从python asyncio引发的集中学习
我比较笨,只看用await asyncio.sleep(x)实现的例子,看再多,也还是不会. 已经在unity3d里用过coroutine了,也知道是“你执行一下,主动让出权限:我执行一下,主动让出权 ...
- 异步协程asyncio+aiohttp
aiohttp中文文档 1. 前言 在执行一些 IO 密集型任务的时候,程序常常会因为等待 IO 而阻塞.比如在网络爬虫中,如果我们使用 requests 库来进行请求的话,如果网站响应速度过慢,程序 ...
- Python爬虫进阶 | 异步协程
一.背景 之前爬虫使用的是requests+多线程/多进程,后来随着前几天的深入了解,才发现,对于爬虫来说,真正的瓶颈并不是CPU的处理速度,而是对于网页抓取时候的往返时间,因为如果采用request ...
- 深入理解协程(二):yield from实现异步协程
原创不易,转载请联系作者 深入理解协程分为三部分进行讲解: 协程的引入 yield from实现异步协程 async/await实现异步协程 本篇为深入理解协程系列文章的第二篇. yield from ...
- python网络-多任务实现之协程(27)
一.协程 协程,又称微线程,纤程.英文名Coroutine. 协程不是进程,也不是线程,它就是一个函数,一个特殊的函数——可以在某个地方挂起,并且可以重新在挂起处继续运行.所以说,协程与进程.线程相比 ...
随机推荐
- Caffe---Pycaffe转换均值文件:xxx_mean.binaryproto成为xxx_mean.npy
Pycaffe转换均值文件:xxx_mean.binaryproto成为xxx_mean.npy 为什么需要mean.binaryproto转mean.npy? 使用Caffe的C++接口进行操作时, ...
- HashSet怎样保证元素不重复
文章同步更新在个人博客:HashSet怎样保证元素不重复 都知道HashSet中不能存放重复元素,有时候可以用来做去重操作等.但是其内部是怎么保证元素不重复的呢?下面从源码去看看. 打开HashSet ...
- python .pth 文件 和 site 模块
python .pth 文件 和 site 模块 .pth 文件 该文件位于 python 的 /Lib/site-packages 目录下,可以有多个,在 .pth 文件中可以把其它目录添加到 sy ...
- VSCode 常用快捷键和常用插件及通用设置
https://code.visualstudio.com/docs?start=true 一.常用快捷键:参考:https://blog.csdn.net/liwan09/article/detai ...
- [NOI2012]骑行川藏——拉格朗日乘子法
原题链接 不会啊,只好现学了拉格朗日乘子法,简单记录一下 前置芝士:拉格朗日乘子法 要求\(n\)元目标函数\(f(x_1,x_2,...,x_n)\)的极值,且有\(m\)个约束函数形如\(h_i( ...
- 12 canvas 画布 - 基础
二.线条的绘制和填充 在canvas中,各个图像绘制代码可以通过beginPath()和closePath()这两个函数进行包裹,主要用于分割各个画图,表示开始和结束.线条的绘制主要调用方法是move ...
- bzoj4009: [HNOI2015]接水果(整体二分)
题目描述 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果.由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更加难的版本. 首先有 ...
- 3、docker常用命令:help、镜像命令、容器命令
1.帮助命令 1.docker version 2.docker info 3.重点掌握:docker --help 2.镜像命令 1.docker,镜像,容器关系 2.docker images ( ...
- js上传整个文件夹
文件夹上传:从前端到后端 文件上传是 Web 开发肯定会碰到的问题,而文件夹上传则更加难缠.网上关于文件夹上传的资料多集中在前端,缺少对于后端的关注,然后讲某个后端框架文件上传的文章又不会涉及文件夹. ...
- bbs-admin
目录 引入单例----单例补充 admin---url/注册的自定义配置 解析admin源码 django-admin注册账号-----创建超级用户 python manage.py createsu ...