Python 异步库 asyncio、aiohttp
asyncio
版本支持
- asyncio 模块在 Python3.4 时发布。
- async 和 await 关键字最早在 Python3.5 中引入。
- Python3.3 之前不支持。
关键概念
event_loop
事件循环:程序开启一个无限的循环,程序员会把一些函数(协程)注册到事件循环上。当满足事件发生的时候,调用相应的协程函数。coroutine
协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用。future
对象: 代表将来执行或没有执行的任务的结果。它和task上没有本质的区别task
任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含任务的各种状态。Task 对象是 Future 的子类,它将 coroutine 和 Future 联系在一起,将 coroutine 封装成一个 Future 对象。async/await
关键字:python3.5 用于定义协程的关键字,async定义一个协程,await用于挂起阻塞的异步调用接口。其作用在一定程度上类似于yield。
工作流程
- 定义/创建协程对象
- 将协程转为task任务
- 定义事件循环对象容器
- 将task任务放到事件循环对象中触发
import asyncioasync def hello(name):print('Hello,', name)# 定义协程对象
coroutine = hello("World")# 定义事件循环对象容器
loop = asyncio.get_event_loop()# 将协程转为task任务
# task = asyncio.ensure_future(coroutine)
task = loop.create_task(coroutine)# 将task任务扔进事件循环对象中并触发
loop.run_until_complete(task)
并发
1. 创建多个协程的列表 tasks:
import asyncioasync def do_some_work(x):print('Waiting: ', x)await asyncio.sleep(x)return 'Done after {}s'.format(x)tasks = [do_some_work(1), do_some_work(2), do_some_work(4)]
2. 将协程注册到事件循环中:
方法一:使用 asyncio.wait()
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
方法二:使用 asyncio.gather()
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(*tasks))
3. 查看 return 结果:
for task in tasks:print('Task ret: ', task.result())
4. asyncio.wait()
与 asyncio.gather()
的区别:
接收参数不同:
asyncio.wait()
:必须是一个 list 对象,list 对象里存放多个 task 任务。
# 使用 asyncio.ensure_future 转换为 task 对象
tasks=[asyncio.ensure_future(factorial("A", 2)),asyncio.ensure_future(factorial("B", 3)),asyncio.ensure_future(factorial("C", 4))
]# 也可以不转为 task 对象
# tasks=[
# factorial("A", 2),
# factorial("B", 3),
# factorial("C", 4)
# ]loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
asyncio.gather()
:比较广泛,注意接收 list 对象时 *
不能省略。
tasks=[asyncio.ensure_future(factorial("A", 2)),asyncio.ensure_future(factorial("B", 3)),asyncio.ensure_future(factorial("C", 4))
]# tasks=[
# factorial("A", 2),
# factorial("B", 3),
# factorial("C", 4)
# ]loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(*tasks))
loop = asyncio.get_event_loop()group1 = asyncio.gather(*[factorial("A" ,i) for i in range(1, 3)])
group2 = asyncio.gather(*[factorial("B", i) for i in range(1, 5)])
group3 = asyncio.gather(*[factorial("B", i) for i in range(1, 7)])loop.run_until_complete(asyncio.gather(group1, group2, group3))
返回结果不同:
asyncio.wait()
:返回 dones
(已完成任务) 和 pendings
(未完成任务)
dones, pendings = await asyncio.wait(tasks)for task in dones:print('Task ret: ', task.result())
asyncio.gather()
:直接返回结果
results = await asyncio.gather(*tasks)for result in results:print('Task ret: ', result)
aiohttp
ClientSession 会话管理
import aiohttp
import asyncioasync def main():async with aiohttp.ClientSession() as session:async with session.get('http://httpbin.org/get') as resp:print(resp.status)print(await resp.text())asyncio.run(main())
其他请求:
session.post('http://httpbin.org/post', data=b'data')
session.put('http://httpbin.org/put', data=b'data')
session.delete('http://httpbin.org/delete')
session.head('http://httpbin.org/get')
session.options('http://httpbin.org/get')
session.patch('http://httpbin.org/patch', data=b'data')
URL 参数传递
async def main():async with aiohttp.ClientSession() as session:params = {'key1': 'value1', 'key2': 'value2'}async with session.get('http://httpbin.org/get', params=params) as r:expect = 'http://httpbin.org/get?key1=value1&key2=value2'assert str(r.url) == expect
async def main():async with aiohttp.ClientSession() as session:params = [('key', 'value1'), ('key', 'value2')]async with session.get('http://httpbin.org/get', params=params) as r:expect = 'http://httpbin.org/get?key=value2&key=value1'assert str(r.url) == expect
获取响应内容
async def main():async with aiohttp.ClientSession() as session:async with session.get('http://httpbin.org/get') as r:# 状态码print(r.status)# 响应内容,可以自定义编码print(await r.text(encoding='utf-8'))# 非文本内容print(await r.read())# JSON 内容print(await r.json())
自定义请求头
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36"}async def main():async with aiohttp.ClientSession() as session:async with session.get('http://httpbin.org/get', headers=headers) as r:print(r.status)
为所有会话设置请求头:
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36"}async def main():async with aiohttp.ClientSession(headers=headers) as session:async with session.get('http://httpbin.org/get') as r:print(r.status)
自定义 cookies
async def main():cookies = {'cookies_are': 'working'}async with aiohttp.ClientSession() as session:async with session.get('http://httpbin.org/cookies', cookies=cookies) as resp:assert await resp.json() == {"cookies": {"cookies_are": "working"}}
为所有会话设置 cookies:
async def main():cookies = {'cookies_are': 'working'}async with aiohttp.ClientSession(cookies=cookies) as session:async with session.get('http://httpbin.org/cookies') as resp:assert await resp.json() == {"cookies": {"cookies_are": "working"}}
设置代理
注意:只支持 http 代理。
async def main():async with aiohttp.ClientSession() as session:proxy = "http://127.0.0.1:1080"async with session.get("http://python.org", proxy=proxy) as r:print(r.status)
需要用户名密码授权的代理:
async def main():async with aiohttp.ClientSession() as session:proxy = "http://127.0.0.1:1080"proxy_auth = aiohttp.BasicAuth('username', 'password')async with session.get("http://python.org", proxy=proxy, proxy_auth=proxy_auth) as r:print(r.status)
也可以直接传递:
async def main():async with aiohttp.ClientSession() as session:proxy = "http://username:password@127.0.0.1:1080"async with session.get("http://python.org", proxy=proxy) as r:print(r.status)
异步爬虫示例
import asyncio
import aiohttpfrom lxml import etree
from datetime import datetimeheaders = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36"}async def get_movie_url():req_url = "https://movie.douban.com/chart"async with aiohttp.ClientSession() as session:async with session.get(url=req_url, headers=headers) as response:result = await response.text()result = etree.HTML(result)return result.xpath("//*[@id='content']/div/div[1]/div/div/table/tr/td/a/@href")async def get_movie_content(movie_url):async with aiohttp.ClientSession() as session:async with session.get(url=movie_url, headers=headers) as response:result = await response.text()result = etree.HTML(result)movie = dict()name = result.xpath('//*[@id="content"]/h1/span[1]//text()')author = result.xpath('//*[@id="info"]/span[1]/span[2]//text()')movie["name"] = namemovie["author"] = authorreturn moviedef run():start = datetime.now()loop = asyncio.get_event_loop()movie_url_list = loop.run_until_complete(get_movie_url())tasks = [get_movie_content(url) for url in movie_url_list]movies = loop.run_until_complete(asyncio.gather(*tasks))print(movies)print("异步用时为:{}".format(datetime.now() - start))if __name__ == '__main__':run()
Python 异步库 asyncio、aiohttp相关推荐
- Python标准库asyncio模块基本原理浅析
Python标准库asyncio模块基本原理浅析 本文环境python3.7.0 asyncio模块的实现思路 当前编程语言都开始在语言层面上,开始简化对异步程序的编程过程,其中Python中也开始了 ...
- python 异步编程——asyncio
python 异步编程--asyncio 摘要 1. 协程 1.1 基本概念 1.2 实现方法 1.2.1 greenlet 1.2.2 yield 1.2.3 asyncio模块 1.2.4 asy ...
- python3异步编程_协程 Python异步编程(asyncio)
协程(Coroutine) 也可以被称为微线程,是一种用户态内的上下文切换技术.简而言之,其实就是通过一个线程实现代码块相互切换执行. 直接上代码,例如: 同步编程 import time def f ...
- python链家网高并发异步爬虫asyncio+aiohttp+aiomysql异步存入数据
python链家网二手房异步IO爬虫,使用asyncio.aiohttp和aiomysql 很多小伙伴初学python时都会学习到爬虫,刚入门时会使用requests.urllib这些同步的库进行单线 ...
- aiohttp保存MySQL_python链家网高并发异步爬虫asyncio+aiohttp+aiomysql异步存入数据
python链家网二手房异步IO爬虫,使用asyncio.aiohttp和aiomysql 很多小伙伴初学python时都会学习到爬虫,刚入门时会使用requests.urllib这些同步的库进行单线 ...
- 前端调用mysql异步_python链家网高并发异步爬虫asyncio+aiohttp+aiomysql异步存入数据...
python链家网二手房异步IO爬虫,使用asyncio.aiohttp和aiomysql 很多小伙伴初学python时都会学习到爬虫,刚入门时会使用requests.urllib这些同步的库进行单线 ...
- aiohttp mysql_python异步爬虫asyncio+aiohttp+aiomysql异步存入数据
异步IO爬虫,使用asyncio.aiohttp和aiomysql 很多小伙伴初学python时都会学习到爬虫,刚入门时会使用requests.urllib这些同步的库进行单线程爬虫,速度是比较慢的, ...
- python异步编程asyncio
前提概要:python因为GIL锁,所以运行都是单线程,导致python运行的速度慢,为此要解决这个问题有多进程.多线程,但是使用这些方法,我们就要多加考虑线程安全问题,顾很麻烦,所以推出了协程.协程 ...
- python 异步编程 asyncio
协程 协程(Coroutine),也可以被称为微线程,是一种用户态内的上下文切换技术.简而言之,其实就是通过一个线程实现代码块相互切换执行 在Python中有多种方式可以实现协程,例如: greenl ...
最新文章
- 百度关键词研究: 应避免的5个错误!
- 如何在自己开发的日程管理页面插入提醒功能_微信中6个藏得很深但却很有用的功能...
- fullpage 单屏高度超过屏幕高度,实现单屏内可以滚动并解决手机端单屏高度不正确的问题
- Translating Embedding for Modeling Multi-relational Data
- Javascript 创建对象方法的总结
- Android系统从驱动到上层服务再到应用的两种服务架构方式
- 转:iOS-CoreLocation:无论你在哪里,我都要找到你!
- Oracle客户端安装
- c语言强化训练作业整理1
- mysql课件_MYSQL讲课时的PPT课件.ppt
- ROS学习(十七)安装ARDUINO IDE使用rosserial
- 基于深度极限学习机DELM的分类
- codesys工程ST语言学习笔记(六)ST语言读写CVS文件excel格式(文件读写)
- 沙雕动画资源素材大全/小白零基础快速入门沙雕动画/三天快速上手开始制作沙雕动画/
- 随机访问介质访问控制 —— ALOHA协议
- 你可能不知道的 Ps 技巧
- vivo怎么切换为Android,vivox60pro如何切换系统 一键切换手机不通系统方法
- 高效缓冲区输入输出流
- Python创建文件夹和子文件夹
- 网页瘦身方法-金瑞帆高端建站
热门文章
- 2020年中国对外直接投资行业发展综述及发展趋势分析[图]
- 风口中的智慧城市:智慧的面子,数字的里子
- 「应用笔记」激光二维码导航混合制图
- 绝世唐门漫画的王秋儿
- IDEA/AndroidStudio 一键为项目中所有文件添加copyright
- 微信读书推出无限卡的一些思考
- 教你玩Robocode(5)——调试技巧
- dirty pipe漏洞,解决办法
- 2021年中考计算机考试,2021年中考这样改革,初一初二考生需提前了解!
- 用计算机求值根号12345,【中考数学专题】特殊角的妙用——“12345模型”