到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。
task1 = asyncio.create_task(func())
task2 = asyncio.create_task(fucn())
# 当执行某协程遇到 IO 操作时,会自动化切换执行其它任务。
# 此处的 await 时等待相对应的协程全都执行完毕并获取结果。
result_1 = await task1
result_2 = await task2
print(result_1, result_2)
asyncio.run(main())
示例 2(这种代码应用得比较多):
import asyncio
async def func():
print(1)
await asyncio.sleep(2)
print(2)
return "返回值"
async def main():
print("main 开始")
# 创建协程任务列表
task_list = [
asyncio.create_task(func(), name="n1"), # 给 task 命名,会在返回集中显示
asyncio.create_task(func(), name="n2")
]
# 不能直接把 task_list 以列表的形式加在 await 之后
# 注意 await 关键字只接受 coroutine object, task object, future object
# 此处 done 是一个集合,为 task_list 的返回值
# pending 在 timeout 不为 None 时有意义,timeout 规定了最长等待时间,
# 如果超过 timeout,那么还未完成的任务将添加到 pending 中。
done, pending = await asyncio.wait(task_list, timeout=1)
print(done)
asyncio.run(main())
示例 3:
import asyncio
async def func():
print(1)
await asyncio.sleep(2)
print(2)
return "返回值"
# 创建协程任务列表
task_list = [
asyncio.create_task(func(), name="n1"), # 给 task 命名,会在返回集中显示
asyncio.create_task(func(), name="n2")
]
done, pending = asyncio.run(asyncio.wait(task_list))
print(done)
注意到以上代码会导致程序报错。原因是:asyncio.create_task()
会将协程对象立即添加到事件循环中,但是,事件循环是在 asyncio.run()
中被创造,因此此时并不存在事件循环。应该如此修改:
import asyncio
async def func():
print(1)
await asyncio.sleep(2)
print(2)
return "返回值"
# 创建协程对象列表
task_list = [
func(),
func()
]
# 此时 asyncio 会在创建事件循环之后,在内部将 task_list 中的协程对象添加到事件循环中
done, pending = asyncio.run(asyncio.wait(task_list))
print(done)
3.5 Future
对象
Future
类是 Task
类的父类,即 Task
类继承自 Future
类,Task
对象内部 await 结果的处理基于 Future
对象而来。
A Future
is a special low-level awaitable object that represents an eventual result of an asynchronous operation.
示例 1:
import asyncio
async def main():
# 获取当前事件循环
loop = asyncio.get_running_loop()
# 创建一个任务(Future 对象),这个任务什么都不干。
future = loop.create_future()
# 等待任务最终结果(Future 对象),没有结果则会一直等下去。
await future
asyncio.run(main())
在上述代码中,由于创建的 Future
对象什么也不干,因此 await future
将一直卡住,无法获得返回结果,所以上述代码是没有实际意义的。但注意,如果某一个时刻突然给 future
赋值,那么 future
立刻可以获得返回结果,并且跳出 await
。
示例 2(没什么意义,用于理解 Future
对象的作用,即帮助我们等待结果):
async def set_after(future):
await asyncio.sleep(2)
future.set_result("666")
async def main():
# 获取当前事件循环
loop = asyncio.get_running_loop()
# 创建一个任务(Future 对象),没有绑定任何行为,则这个任务永远不知道什么时候结束。
future = loop.create_future()
# 创建一个任务(Task 对象),绑定了 set_after 函数,函数内部在 2s 之后会给 future 赋值。
# 即手动设置 future 任务的最终结果,那么 future 就可以结束了。
await loop.create_task(set_after(future))
# 等待 Future 对象获取最终结果,否则一直等待下去。
data = await future
print(data)
asyncio.run(main())
3.6 concurrent
中的 Future
对象
首先注意到,concurrent
中的 Future
对象(concurrent.futures.Future
)和 asyncio
中的 Future
对象没有关系。concurrent
中的 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)
return value
# 创建线程池
pool = ThreadPoolExecutor(max_workers=5)
# 或创建进程池
# pool = ProcessPoolExecutor(max_workers=5)
for i in range(10):
# 让 pool 拿出一个线程去执行 func 函数
future = pool.submit(func, i)
print(future)
实际中可能会存在两种 Futu