You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python asyncio中await Future疑似阻塞问题及替代方案咨询

问题分析与解决方案

问题根源:不是GIL的问题,是代码逻辑和API使用错误

你的代码问题和GIL完全无关,核心错误有三个:

  1. 任务执行顺序颠倒:你先await wait_on_data(fut),此时Future还未被设置结果,wait_on_data会一直等待直到超时;等超时返回后才提交set_status执行,这时候已经来不及设置Future结果了。
  2. run_in_executor使用错误:run_in_executor需要传入可调用对象和参数,你直接调用set_status(fut)会导致函数立即执行(且此时已经超时),而非提交到线程池异步执行。正确用法是run_in_executor(None, set_status, fut),第一个参数为None表示使用默认线程池。
  3. 断言逻辑错误:wait_on_data返回的是元组(True, True)或(False, False),但你断言result == True,这永远会失败,因为元组和布尔值不相等。

修正后的代码示例

方案1:用线程池执行同步函数set_status

import asyncio

def set_status(fut):
    print("set future")
    fut.set_result((True, True))
    
async def wait_on_data(fut):
    try:
        async with asyncio.timeout(10):
            print("waiting for future")
            await fut
            return fut.result()
    except TimeoutError:
        print("timeout for future")
        return (False, False)
   
async def main():
    loop = asyncio.get_running_loop()
    fut = loop.create_future()
    # 先提交set_status到线程池异步执行,再等待Future结果
    await loop.run_in_executor(None, set_status, fut)
    result = await wait_on_data(fut)
    
    # 修正断言逻辑
    assert result == (True, True), "Result mismatch"
    print("Success, result:", result)

asyncio.run(main())

方案2:改为异步函数用create_task调度

如果set_status本身不需要阻塞线程(仅处理异步逻辑),可以改成异步函数,用asyncio.create_task直接调度:

import asyncio

async def set_status(fut):
    print("set future")
    fut.set_result((True, True))
    
async def wait_on_data(fut):
    try:
        async with asyncio.timeout(10):
            print("waiting for future")
            await fut
            return fut.result()
    except TimeoutError:
        print("timeout for future")
        return (False, False)
   
async def main():
    fut = asyncio.get_running_loop().create_future()
    # 创建异步任务并立即调度
    asyncio.create_task(set_status(fut))
    result = await wait_on_data(fut)
    
    assert result == (True, True), "Result mismatch"
    print("Success, result:", result)

asyncio.run(main())

关键说明

  • 异步编程核心是先调度任务,再等待结果,不能先等待再调度,否则必然超时。
  • run_in_executor用于将同步阻塞函数放到线程池执行,避免阻塞事件循环;纯异步逻辑直接用create_task更高效。
  • Future的set_result是线程安全的,不管在事件循环线程还是线程池里调用都能正确设置结果。

内容的提问来源于stack exchange,提问作者zzcc0909

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 07:15:38