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

pytest参数化时asyncio协程复用触发RuntimeError的解决方案问询

解决异步函数lru_cache导致的协程重复await错误

问题核心

你遇到的RuntimeError: cannot reuse already awaited coroutine,根源是@lru_cache直接装饰异步函数时,缓存的是协程对象实例——而协程对象只能被await一次。当参数化的不同输入(整数28815543和字符串"28815543")生成同一个IdReference实例时,会命中同一个缓存的协程对象,第二次await就触发了错误。

解决办法(无需拆分参数化)

1. 缓存异步函数的执行结果而非协程对象

替换原生@lru_cache为自定义装饰器,缓存函数的返回值而非协程实例:

from functools import wraps, lru_cache

def async_lru_cache(maxsize=128):
    def decorator(func):
        # 用lru_cache缓存异步函数的最终结果
        @lru_cache(maxsize=maxsize)
        async def cached_execution(*args, **kwargs):
            return await func(*args, **kwargs)
        
        @wraps(func)
        async def wrapper(*args, **kwargs):
            return await cached_execution(*args, **kwargs)
        
        # 暴露缓存清理方法,方便测试时重置
        wrapper.cache_clear = cached_execution.cache_clear
        return wrapper
    return decorator

用这个装饰器替代@lru_cache修饰fetch.summary:

@async_lru_cache()
async def summary(id_ref):
    # 原函数逻辑

这样每次调用都会生成新的协程对象,缓存的是最终计算结果,彻底避免重复await同一个协程的问题。

2. 测试用例执行后自动清理缓存

如果不想修改业务代码,可以通过pytest的自动fixture在每个测试用例结束后清空缓存:

import pytest

@pytest.fixture(autouse=True)
def clear_fetch_cache():
    yield
    # 清空fetch.summary的缓存
    fetch.summary.cache_clear()

这个fixture会自动在每个测试用例执行完毕后重置缓存,确保不同参数化用例的缓存互相隔离。

3. 调整缓存key的生成逻辑

如果允许修改IdReference的实现,可以调整其__hash__和__eq__方法,让原始输入的类型(整数/字符串)也参与缓存key的计算,确保不同输入生成不同的缓存条目:

class IdReference:
    def __init__(self, raw_id):
        self.external_id = str(raw_id)
        self.raw_type = type(raw_id)  # 保留原始输入类型
    
    def __hash__(self):
        return hash((self.external_id, self.raw_type))
    
    def __eq__(self, other):
        return (self.external_id == other.external_id) and (self.raw_type == other.raw_type)

这样整数和字符串的raw_id会生成不同的IdReference实例,避免命中同一个缓存。

总结

不需要强制拆分参数化,上述三种方法都可以解决问题:

  • 优先推荐缓存异步函数结果的方案,从根源避免协程重复await的问题;
  • 测试层面的缓存清理是快速临时解决方案;
  • 调整IdReference的哈希逻辑适合允许修改业务模型的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 20:42:01