协程函数定义
协程函数以async开头
import asyncio
import time
#定义一个协程函数
async def func():
# time.sleep(5)
print('AAAAAAAAAAA')
#得到协程对象
res = func()
#创建事件循环
loop = asyncio.get_event_loop()
#将协程对象加入到事件循环中
loop.run_until_complete(res)
# #python 3.7 可直接使用asyncio.run方法
# asyncio.run(res)
await
'''await + 可等待对象(协程对象,Task对象,IO等待)'''
import asyncio
#创建协程函数
async def func():
print('BBBB')
response = await func_others() #此处执行等待协程函数执行完毕,并返回值给response,之后继续往下执行
print('CCCC',response)
async def func_others():
print('DDDD')
await asyncio.sleep(2)
print('EEEE')
return 'FFFF'
#创建事件循环
loop = asyncio.get_event_loop()
loop.run_until_complete(func())
运行结果:
Future对象
'''Task 继承Future对象,Task内部await结果处理基于future对象结果
future 有两种类型,一种是
'''
import asyncio
async def setValue(fut):
'''延时2秒给fut对象赋值'''
await asyncio.sleep(2)
fut.set_result(2)
async def main():
#获取当前事件循环
loop = asyncio.get_running_loop()
#创建一个任务,future对象,并指定函数参数
fut = loop.create_future()
#创建任务并将协程对象赋值给任务
await loop.create_task(setValue(fut))
#等待任务最终结果,没有结果一直等待下去
data = await fut
print(data)
asyncio.run(main())
concurrent.futures.Tuture
'''
future对象有两种类型
1、通过事件循环创建future对象
2、concurrent.futures.Tuture 对象 ---使用线程池或者进程池来实现异步操作
'''
import time
from concurrent.futures import Future
from concurrent.futures.thread import ThreadPoolExecutor
from concurrent.futures.process import ProcessPoolExecutor
#定普通函数
def func(value):
time.sleep(2)
print(value)
if __name__ == '__main__':
#创建一个线程数为5线程池
pool = ThreadPoolExecutor(max_workers=5)
for i in range(10):
fut = pool.submit(func,1) #通过线程池的方式返回future
print(fut)
task
'''task:在事件循环中添加多个任务'''
import asyncio
import time
async def func():
print(1)
#线程等待
await asyncio.sleep(9)
print(2)
return 3
async def main():
print('---START---')
#创建task任务列表
task_list = [
asyncio.create_task(func(),name='test_01'),
asyncio.create_task(func(),name='test_02')
]
print('---END---')
done,pending = await asyncio.wait(task_list,timeout=None)
print(done)
asyncio.run(main()) #python3.7写法
打印结果:
task优化写法
task_list = [
#直接在此处创建协程对象
func(),
func()
]
done,pending = asyncio.run(asyncio.wait(task_list))
print(done)
两种不同类型的future结合使用,在不支持异步的模块中使用异步编程(常用)
'''协程异步 + requests(不支持)场景(协程函数中调用普通函数)'''
import time
import asyncio
import requests
import concurrent.futures
def func():
#某个耗时操作
time.sleep(2)
return 2
async def main():
loop = asyncio.get_running_loop()
#第一步:内部会先调用 ThreadPoolExecutor的submit方法去申请一个线程执行func函数,并返回一个concurrent.futures.Future对象
#第二部:调用asyncio.wrap_futures.future方法将concurrent.future.Future对象包装成为asyncio.future对象
#因为concurrent.future.Future对象不支持await方法,所以需要包装
fut = loop.run_in_executor(None,func)
result = await fut
print('default thread pool',result)
#案例
async def dowmload_images(url):
print('开始下载:%s'% url)
#发送IO请求
loop = asyncio.get_event_loop()
#requests模块不支持异步操作,故使用线程池来实现
future = loop.run_in_executor(None,requests.get,url)
response = await future
print('%s:下载完成...',url)
#本地存储
file_name = url.split('_')[-1]
with open(file_name,'wb') as f:
f.write(response.content)
if __name__ == '__main__':
# asyncio.run(main())
url_list = ['https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1608562578327&di=3a5b6a9e81dbfffeb9591331b98f1364&imgtype=0&src=http%3A%2F%2Fpic.jj20.com%2Fup%2Fallimg%2F1113%2F041620103S8%2F200416103S8-4-1200.jpg',
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1608562578327&di=3a5b6a9e81dbfffeb9591331b98f1364&imgtype=0&src=http%3A%2F%2Fpic.jj20.com%2Fup%2Fallimg%2F1113%2F041620103S8%2F200416103S8-4-1200.jpg',
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1608562578327&di=3a5b6a9e81dbfffeb9591331b98f1364&imgtype=0&src=http%3A%2F%2Fpic.jj20.com%2Fup%2Fallimg%2F1113%2F041620103S8%2F200416103S8-4-1200.jpg'
]
#创建协程
tasks = [dowmload_images(url) for url in url_list]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))