Python异步操作实现及TypeError报错排查:如何让接口非阻塞
问题分析与解决方案
1. 直接触发错误的核心原因:async for误用
报错'async for' requires an object with __aiter__ method, got coroutine,本质是你把普通可迭代对象当成了异步可迭代对象来处理:
- 代码里的
summary_result应该是笔误,实际是await self.s3_client.fetch()返回的s_result,它是普通的Python列表/字典,不是异步迭代器,完全不需要用async for遍历,直接用普通for循环即可。
修正服务层代码这部分:
async def refresh_data(): try: s_result = await self.s3_client.fetch() except (FileNotFound, IOError) as e: logger.info("problem") # 移除async关键字,用普通for循环遍历同步可迭代对象 gather = {i.pop("x"):i for i in s_result} # ... 其他操作
2. 控制器层的非阻塞实现修正
当前控制器是同步函数,直接调用myservice.refresh_data()(async函数)只会返回一个协程对象,根本不会实际执行;要实现非阻塞不影响其他接口,需要:
- 改用异步Web框架(比如FastAPI、Flask 2.0+),将控制器改为异步函数
- 用
asyncio.create_task把刷新数据的任务丢到后台执行,接口立即返回响应
以FastAPI为例的控制器代码:
from fastapi import FastAPI import asyncio app = FastAPI() @app.post("/refresh_data") async def refresh_data(): # 后台异步执行刷新任务,不等待完成 asyncio.create_task(myservice.refresh_data()) return {"ok": True}
以Flask 2.0+为例的控制器代码:
from flask import Flask, jsonify import asyncio app = Flask(__name__) @app.route("/refresh_data", methods=["POST"]) async def refresh_data(): asyncio.create_task(myservice.refresh_data()) return jsonify({"ok": True})
3. 客户端同步IO的阻塞问题修复
pd.read_parquet是同步IO操作,直接在async函数里调用会阻塞整个asyncio事件循环,导致其他接口也被卡住,完全违背非阻塞需求。需要把这个同步操作放到线程池里执行:
修正客户端代码:
import asyncio import pandas as pd async def fetch(): # 用asyncio.to_thread将同步IO任务丢到线程池,避免阻塞事件循环 result = await asyncio.to_thread( pd.read_parquet, "s3://bucket/your_file.parquet", # 补充完整S3路径 engine="pyarrow", columns=cols, filters=filts ) return result.to_dict(orient="col1")
额外注意事项
- 如果有异步S3客户端(比如
aioboto3),优先使用异步客户端,比线程池+同步客户端的效率更高 - 后台任务要做好异常捕获,避免任务崩溃牵连整个服务
- 用Flask时,需搭配异步WSGI服务器(比如hypercorn)启动,才能真正发挥异步优势
内容的提问来源于stack exchange,提问作者Saturnian
相关产品推荐
相关产品推荐

