3.5 asyncio.Future对象
A `Future`is a special **low-level** awaitable object that represents an **eventual result** of an asynchronous operation.
Task继承Future,Task对象内部await结果的处理基于Future对象来的。
示例1:
async def main(): # 获取当前事件循环 loop = asyncio.get_running_loop() # 创建一个任务(Future对象),这个任务什么都不干。 fut = loop.create_future() # 等待任务最终结果(Future对象),没有结果则会一直等下去。 await fut asyncio.run( main() )
示例2:
import asyncio async def set_after(fut): await asyncio.sleep(2) fut.set_result("666") async def main(): # 获取当前事件循环 loop = asyncio.get_running_loop() # 创建一个任务(Future对象),没绑定任何行为,则这个任务永远不知道什么时候结束。 fut = loop.create_future() # 创建一个任务(Task对象),绑定了set_after函数,函数内部在2s之后,会给fut赋值。 # 即手动设置future任务的最终结果,那么fut就可以结束了。 await loop.create_task( set_after(fut) ) # 等待 Future对象获取 最终结果,否则一直等下去 data = await fut print(data) asyncio.run( main() )
### 3.6 concurrent.futures.Future对象
使用线程池、进程池实现异步操作时用到的对象。
import time from concurrent.futures import Future from concurrent.futures.thread import ThreadPoolExecutor from concurrent.futures.process import ProcessPoolExecutor def func(value): time.sleep(1) print(value) return 123 <P># 创建线程池</P> pool = ThreadPoolExecutor(max_workers=5) <P># 创建进程池</P> # pool = ProcessPoolExecutor(max_workers=5) for i in range(10): fut = pool.submit(func, i) print(fut)
以后写代码可能会存在交叉时间。例如:crm项目80%都是基于协程异步编程 + MySQL(不支持)【线程、进程做异步编程】。
import time import asyncio import concurrent.futures def func1(): # 某个耗时操作 time.sleep(2) return "SB" async def main(): loop = asyncio.get_running_loop() # 1. Run in the default loop's executor ( 默认ThreadPoolExecutor ) # 第一步:内部会先调用 ThreadPoolExecutor 的 submit 方法去线程池中申请一个线程去执行func1函数,并返回一个concurrent.futures.Future对象 # 第二步:调用asyncio.wrap_future将concurrent.futures.Future对象包装为asycio.Future对象。 # 因为concurrent.futures.Future对象不支持await语法,所以需要包装为 asycio.Future对象 才能使用。 fut = loop.run_in_executor(None, func1) result = await fut print('default thread pool', result) # 2. Run in a custom thread pool: # with concurrent.futures.ThreadPoolExecutor() as pool: # result = await loop.run_in_executor( # pool, func1) # print('custom thread pool', result) # 3. Run in a custom process pool: # with concurrent.futures.ProcessPoolExecutor() as pool: # result = await loop.run_in_executor( # pool, func1) # print('custom process pool', result) asyncio.run( main() )
案例:asyncio + 不支持异步的模块
import asyncio import requests async def download_image(url): # 发送网络请求,下载图片(遇到网络下载图片的IO请求,自动化切换到其他任务) print("开始下载:", url) loop = asyncio.get_event_loop() # requests模块默认不支持异步操作,所以就使用线程池来配合实现了。 future = loop.run_in_executor(None, requests.get, url) response = await future print('下载完成') # 图片保存到本地文件 file_name = url.rsplit('_')[-1] with open(file_name, mode='wb') as file_object: file_object.write(response.content) if __name__ == '__main__': url_list = [ 'https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar__ChsEe12AXQ6AOOH_AAFocMs8nzU621.jpg', 'https://www2.autoimg.cn/newsdfs/g30/M01/3C/E2/120x90_0_autohomecar__ChcCSV2BBICAUntfAADjJFd6800429.jpg', 'https://www3.autoimg.cn/newsdfs/g26/M0B/3C/65/120x90_0_autohomecar__ChcCP12BFCmAIO83AAGq7vK0sGY193.jpg' ] tasks = [ download_image(url) for url in url_list] loop = asyncio.get_event_loop() loop.run_until_complete( asyncio.wait(tasks) )