1、协程管理——asyncio
协程又称微线程,完全由程序控制,协程切换花销小,因而有更高的性能。
python中使用asynico 来作为协程的管理包
python使用asyns 与await 关键字来进行协程控制
async def work():
pass
在协程中除了普通函数的功能外最主要的作用就是:使用 await 语法等待另一个协程结束,这将挂起当前协程,直到另一个协程产生结果再继续执行:
async def work(sleepTime):
await asyncio.sleep(sleepTime)
print('continue')
asyncio.sleep() 是 asyncio 包内置的协程函数,这里模拟耗时的IO操作,上面这个协程执行到这一句会挂起当前协程而去执行其他协程,直到sleep结束,当有多个协程任务时,这种切换会让它们的IO操作并行处理
执行一个协程函数并不会真正的去运行它,而是会返回一个协程对象
在 Python3.7+ 中,运行asyncio 程序只需要一句:asyncio.run(work()) ,而在 Python3.6 中,需要手动获取事件循环并加入协程任务:
loop = anyncio.get_event_loop()
loop.run_until_complete(work(1))
loop.close()
事件循环就是一个循环队列,对其中的协程进行调度执行,当把一个协程加入循环,这个协程创建的其他协程都会自动加入到当前事件循环中
其实协程对象也不是直接运行,而是被封装成一个个待执行的 Task ,大多数情况下 asyncio 会帮我们进行封装,我们也可以提前自行封装 Task 来获得对协程更多的控制权
python3.7使用asyncio.create_task() 进行封装,而python3.6需要使用asyncio.ensure_future() 来进行封装
taskList = [asyncio.create_task(work(num)) for num in range(1, 5)]
task = asyncio.create_task(asyncio.await(taskList))
task = asyncio.ensure_future(asyncio.await(taskList))
协程下面可以套用多层协程,但是每一层必须全部是协程
2、异步http库——aiohttp
asyncio不直接支持http的异步并发请求(只支持tcp与udp请求),因此需要引入异步http库aiohttp
使用pip安装aiohttp
pip3 install aiohttp
aiohttp的用法与requests库很相似
get请求
import aiohttp
import asyncio
"""
aiohttp:发送http请求
1.创建一个ClientSession对象
2.通过ClientSession对象去发送请求(get, post, delete等)
3.await 异步等待返回结果
"""
async def main():
url = 'http://httpbin.org/get'
async with aiohttp.ClientSession() as session:
async with session.get(url) as res:
print(res.status)
print(await res.text())
loop = asyncio.get_event_loop()
task = loop.create_task(main())
loop.run_until_complete(task)
post请求
import aiohttp
import asyncio
"""
aiohttp:发送POST请求
"""
async def main():
data = {'key1': 'value1', 'key2': 'value2'}
url = 'http://httpbin.org/post'
async with aiohttp.ClientSession() as session:
async with session.post(url, data=data) as res:
print(res.status)
print(await res.text())
loop = asyncio.get_event_loop()
task = loop.create_task(main())
loop.run_until_complete(task)
自定义请求头
headers = {'content-type': 'image/gif'}
session.post(url, data=data, headers=headers)
传递参数
import aiohttp
import asyncio
"""
aiohttp:传递参数
方式一:通过字典的形式 params = {'key1': 'value1', 'key2': 'value2'}
方式二:通过二元组的形式 params = [('key', 'value1'), ('key', 'value2')]
"""
async def main():
url = 'http://httpbin.org/get'
params = {'key1': 'value1', 'key2': 'value2'}
async with aiohttp.ClientSession() as session:
async with session.get(url, params=params) as res:
print(res.url)
print(await res.text())
loop = asyncio.get_event_loop()
task = loop.create_task(main())
loop.run_until_complete(task)
状态码与响应内容
import aiohttp
import asyncio
"""
aiohttp:相应内容与状态码
状态码:res.status
响应内容:res.text() 或者 res.text(encoding='utf-8')
二进制内容:res.read()
json响应内容:res.json()
读取流:res.content.read(size)
"""
async def main():
url = 'https://api.github.com/events'
async with aiohttp.ClientSession() as session:
async with session.get(url) as res:
print(res.status)
print(await res.text())
print('**********************************')
print(await res.read())
loop = asyncio.get_event_loop()
task = loop.create_task(main())
loop.run_until_complete(task)
封装一个并发的Http类
class Http:
client = None
@classmethod
async def init(cls):
if cls.client is None:
cls.client = aiohttp.ClientSession()
@classmethod
async def get(cls, *args, **kargs):
await cls.init()
return await cls.client.get(*args, **kargs)
@classmethod
async def post(cls, *args, **kargs):
await cls.init()
return await cls.client.post(*args, **kargs)
@classmethod
async def close(cls):
if cls.client is not None:
await cls.client.close()
cls.client = None
参考
python协程之asyncio
Python之异步http库–aiohttp
使用asyncio + aiohttp实现异步的requests API接口
|