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

Python 3.6中await调用赋值变量的协程为何报错?如何解决?

问题原因

这个AssertionError("yield from wasn't used with future",)错误看起来是asyncio内部的断言失败,但本质根源是文件对象arc是线程不安全的:当你把arc.read提交到线程池后,主线程继续执行循环逻辑,此时线程池中的read操作可能还未完成,共享的文件对象会出现并发访问的竞争条件——这会打乱asyncio Future的内部状态,最终触发断言检查失败。

当你把await和run_in_executor写在一行时,主线程会等待read操作完全结束后再继续,文件指针的移动是串行的,不会有竞争;但拆分写法中,你先提交read任务就直接修改arc_offs进入下一次循环,线程池的read操作和主线程的逻辑出现重叠,导致文件操作的状态混乱,进而影响了Future的正常生命周期。

另外还有个潜在问题:你手动维护的arc_offs偏移量,和arc.read自动移动的文件指针可能在并发场景下不一致,导致读取的数据完全不符合预期。

解决方案

要让拆分写法正常工作,核心是避免线程池任务共享同一个线程不安全的文件对象,改用手动控制偏移量的独立读取方式,确保每个线程池任务的读取操作互不干扰。

方案1:使用文件描述符实现安全的异步读取

用os.open获取文件描述符,配合os.read指定读取长度,这样每个线程池任务的读取都是独立的,不会互相影响:

import os
import asyncio as aio

# ... 你的其他初始化代码(如io_exec、hasher等) ...

read_ftr: aio.Future = None
hash_ftr: aio.Future = None
chunk = None
arc_offs = 0
arc_size = os.path.getsize(arc_path)
max_chunk_size = 1024 * 1024  # 示例值,可根据实际调整

# 用文件描述符打开文件,避免线程不安全的文件对象共享
fd = os.open(arc_path, os.O_RDONLY)
try:
    while arc_offs < arc_size:
        chunk_size = min(arc_size - arc_offs, max_chunk_size)
        if read_ftr:
            chunk = await read_ftr
        # 提交独立的读取任务,基于文件描述符而非共享文件对象
        read_ftr = evt_loop.run_in_executor(io_exec, os.read, fd, chunk_size)
        arc_offs += chunk_size
        
        if not chunk:
            continue
        if hash_ftr:
            await hash_ftr
        hash_ftr = hasher.async_update(chunk)
        if hash_ftr:
            await hash_ftr
    await hasher.async_digest()
finally:
    os.close(fd)

方案2:保持文件对象但取消异步重叠

如果你坚持使用open的文件对象,需要确保每次提交新的read任务前,上一次的read已经完成——这种写法不会报错,但会失去异步重叠的性能优势:

import asyncio as aio

# ... 你的其他初始化代码 ...

read_ftr: aio.Future = None
hash_ftr: aio.Future = None
chunk = None
arc_offs = 0
arc_size = os.path.getsize(arc_path)
max_chunk_size = 1024 * 1024

with open(arc_path, "rb") as arc:
    while arc_offs < arc_size:
        chunk_size = min(arc_size - arc_offs, max_chunk_size)
        # 先提交读取任务并等待完成,再继续后续逻辑
        read_ftr = evt_loop.run_in_executor(io_exec, arc.read, chunk_size)
        chunk = await read_ftr
        arc_offs += chunk_size
        
        if not chunk:
            continue
        if hash_ftr:
            await hash_ftr
        hash_ftr = hasher.async_update(chunk)
        if hash_ftr:
            await hash_ftr
await hasher.async_digest()

补充说明

asyncio的run_in_executor返回的是完全合法的asyncio Future,拆分写法本身没有语法问题,问题出在线程不安全资源的并发访问上。错误信息看似和Future相关,实际上是底层IO竞争导致Future的内部状态异常,触发了asyncio的断言检查。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:31:39