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)]
# python3.7
task = asyncio.create_task(asyncio.await(taskList))
# python3.6
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:
# http://httpbin.org/get?key1=value1&key2=value2
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