如何在multiprocessing新进程中调用异步函数?FastAPI Webhook异步任务报错及无输出问题解决
问题分析与解决方案
首先来说第一个错误:RuntimeWarning: coroutine 'loop' was never awaited。这是因为multiprocessing.Process的target参数只接收普通函数,但你传了一个异步协程函数loop。Process只会直接调用这个函数,不会自动处理协程的await逻辑,所以就抛出了这个警告。
你后来改成用preloop包裹asyncio.run(loop(fruit))是正确的思路,但为什么没输出?问题出在同步阻塞的time.sleep彻底破坏了asyncio的事件循环。
asyncio的事件循环是单线程的,一旦你在协程里调用了同步的time.sleep,整个事件循环会被完全卡住,根本没时间去处理其他异步任务。你的loop函数里用了time.sleep(1),这会让事件循环每次都被阻塞1秒,连你用create_task创建的printmessage任务都没机会执行;同样printmessage里的time.sleep(5)也是同步阻塞,就算侥幸执行到了,也会把事件循环卡5秒。
修复后的完整代码
import time from fastapi import Request, FastAPI import multiprocessing as mp import uvicorn import asyncio async def printmessage(fruit): print(fruit) # 把同步的time.sleep换成异步的asyncio.sleep await asyncio.sleep(5) async def loop(fruit): while True: task = asyncio.create_task(printmessage(fruit)) # 同样替换成异步sleep await asyncio.sleep(1) def preloop(fruit): asyncio.run(loop(fruit)) fruit="apple" if __name__ == '__main__': print("PROGRAM LAUNCH...") print("WEBHOOK RECEIVE READY...") app = FastAPI() @app.post("/webhook") async def webhook(request : Request): print("WEBHOOK RECEIVED") p = mp.Process(target=preloop,args=[fruit]) p.start() print('done') return 'WEBHOOK RECEIVED'
为什么这样能解决问题?
- 用
asyncio.run启动协程:preloop作为普通函数,用asyncio.run(loop(fruit))来正确启动异步事件循环,彻底解决了协程未被await的警告。 - 替换同步sleep为异步sleep:
await asyncio.sleep()会把当前协程挂起,让事件循环去处理其他任务(比如你创建的printmessage任务),这样loop可以每隔1秒就创建一个新的printmessage任务,完全不用等待之前的任务完成,实现你想要的“无需等待printmessage执行完成即可执行loop下一行”的效果。 - 多进程隔离:用
multiprocessing.Process启动新进程,避免异步事件循环和FastAPI的主事件循环互相干扰。
这样运行后,你就能看到每1秒打印一次apple的预期输出了。
内容的提问来源于stack exchange,提问作者jguy
相关产品推荐
相关产品推荐

