Future 对象
Future 是一种特殊的低层级可等待对象(Task是Future的子类), 表示一个异步操作的最终结果
当一个 Future 对象被等待, 这意味着协程将保持等待直到该 Future 对象在其他地方操作完毕
async def main():
# 获取当前事件循环
loop = asyncio.get_running_loop()
# 创建一个任务(Future对象), 默认未绑定任何行为, 则这个任务永远都不会结束
fut = loop.create_futute()
# 等到任务最终结果(Future对象), 没有结果则会一直等待下去
await fut
import asyncio
async def set_after(fut):
await asyncio.sleep(2)
fut.set_result('666')
async def main():
loop = asyncio.get_running_loop()
fut = loop.create_future()
# 创建一个任务, 绑定了 set_after 函数, 函数内部在 2s 后, 会给 fut 赋值
# 手动设置 future任务的最终结果, 那么 fut 就可以结束了
await loop.create_task(set_after(fut))
data = await fut
print(data)
asyncio.run(main())
Future 对象本身无函数进行绑定, 想要让事件循环获取 Future 的结果, 则需要手动设置
Task 对象继承了 Future 对象并进行了扩展, 可以实现在对应绑定的函数执行完成之后, 自动执行 set_result
, 从而实现自动结束
concurrent.futures
在 python 的 concurrent.futures
模块中也有一个 Future 对象, 这个对象是基于线程池或进程池实现异步操作时使用的对象
import time
from concurrent.futures import Future
from concurrent.futures.thread import ThreadPoolExecutor
def func(value):
time.sleep(1)
print(value)
pool = ThreadPoolExecutor(max_workers=5)
for i in range(1):
fut = pool.submit(func, i)
print(fut)
示例: async + requests
(1) 直接使用, 实际表现形式为同步请求
import asyncio
import requests
async def send_req(url):
print(f'开始请求 {
url}')
res = requests.get(url).text
print(res)
print(f'请求结束 {
url}')
return res
async def main():
tasks = [
asyncio.create_task(send_req('http://httpbin.org/ip')),
asyncio.create_task(send_req('http://httpbin.org/headers')),
]
await asyncio.wait(tasks)
asyncio.run(main())
(2) run_in_executor 异步请求
import asyncio
import requests
import concurrent.futures
def send_req(url):
print(f'开始请求 {
url}')
res = requests.get(url).text
print(res)
print(f'请求结束 {
url}')
return res
async def main():
loop = asyncio.get_running_loop()
# None, 默认采用 ThreadPoolExecutor 线程池
# 第一步:内部会先调用 ThreadPoolExecutor 的 submit 方法去线程池中申请一个线程去执行 send_req 函数,并返回一个concurrent.futures.Future对象
# 第二步:调用 asyncio.wrap_future 将 concurrent.futures.Future 对象包装为 asycio.Future 对象
tasks = [
loop.run_in_executor(None, send_req, 'http://httpbin.org/ip'),
loop.run_in_executor(None, send_req, 'http://httpbin.org/headers')
]
await asyncio.wait(tasks)
# concurrent.futures 异步
async def main():
loop = asyncio.get_running_loop()
with concurrent.futures.ThreadPoolExecutor() as pool:
tasks = [
loop.run_in_executor(pool, send_req, 'http://httpbin.org/ip'),
loop.run_in_executor(pool, send_req, 'http://httpbin.org/user-agent'),
]
await asyncio.wait(tasks)
asyncio.run(main())
当项目以协程式的异步编程开发时,如果要使用一个第三方模块,而第三方模块不支持协程方式异步编程时,就可以用到这个功能