Flask中异步函数阻塞其他请求问题排查
Flask启动时运行异步函数导致请求无法响应的问题分析与解决
问题根源
你直接在代码中调用asyncio.run(get_new_prices()),这个函数会启动异步事件循环并阻塞主线程,直到get_new_prices()协程完全执行完毕。这就导致Flask的app.run()根本没机会启动服务器,或者服务器启动前就被卡住,自然无法处理任何外部请求。
解决方案
方案一:用后台线程执行异步任务
把异步任务放到独立线程中运行,让主线程能正常启动Flask服务器:
from flask import Flask, request, jsonify from flask_cors import CORS import asyncio import time from scraper import scrap from threading import Thread DEBUG = True app = Flask(__name__) app.config.from_object(__name__) CORS(app) @app.route('/api/v1/request', methods=['POST']) def process_order(): # 你的业务代码 return jsonify({"status": "success"}) async def get_new_prices(): print('async started') start = time.time() res = await scrap() end = time.time() - start print(res, end) def run_async_task(): # 创建新的事件循环用于线程内执行异步任务 loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop.run_until_complete(get_new_prices()) if __name__ == '__main__': # 启动后台守护线程,随主进程退出而终止 Thread(target=run_async_task, daemon=True).start() app.run(debug=DEBUG)
方案二:用任务调度扩展管理后台任务
如果需要定时重复执行该异步任务,或者更规范地管理后台任务,可以使用Flask-APScheduler:
from flask import Flask, request, jsonify from flask_cors import CORS from flask_apscheduler import APScheduler import asyncio import time from scraper import scrap DEBUG = True app = Flask(__name__) app.config.from_object(__name__) CORS(app) # 配置调度器 app.config['SCHEDULER_API_ENABLED'] = True scheduler = APScheduler() @app.route('/api/v1/request', methods=['POST']) def process_order(): # 你的业务代码 return jsonify({"status": "success"}) async def get_new_prices(): print('async started') start = time.time() res = await scrap() end = time.time() - start print(res, end) def run_async_task(): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop.run_until_complete(get_new_prices()) if __name__ == '__main__': scheduler.init_app(app) # 添加启动时执行的一次性任务 scheduler.add_job(id='startup_scrap_task', func=run_async_task, trigger='date') scheduler.start() app.run(debug=DEBUG)
方案三:改用原生支持异步的框架(FastAPI)
如果你的应用有大量异步操作需求,直接切换到FastAPI会更适配,它原生支持异步任务和启动事件:
from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware import asyncio import time from scraper import scrap app = FastAPI() # 配置CORS app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.post("/api/v1/request") async def process_order(): # 你的业务代码 return {"status": "success"} async def get_new_prices(): print('async started') start = time.time() res = await scrap() end = time.time() - start print(res, end) @app.on_event("startup") async def startup_event(): # 将异步任务加入事件循环,不阻塞服务器启动 asyncio.create_task(get_new_prices()) if __name__ == '__main__': import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)
总结
核心问题就是asyncio.run()阻塞了主线程,导致Flask服务器无法正常启动。根据你的实际需求选择方案:简单场景用后台线程,需要任务调度用扩展,大量异步操作优先考虑FastAPI。
内容的提问来源于stack exchange,提问作者Evan Serg
相关产品推荐
相关产品推荐

