我正在使用 FastAPI 和 uvloop 以有效的方式提供 REST API。
我有很多异步代码来调用远程资源,例如数据库、存储等,这些函数如下所示:
async def _get_remote_resource(key: str) -> Resource:
# do some async work
return resource
我正在实现一个现有抽象基类的接口,我需要在同步方法中使用上面的异步函数。我做过类似的事情:
class Resource:
def __str__(self):
resource = asyncio.run_until_complete(_get_remote_resource(self.key))
return f"{resource.pk}"
伟大的!现在我在 fastapi 中创建一个端点以使这项工作可访问:
@app.get("")
async def get(key):
return str(Resource(key))
问题是 FastAPI 已经使用 uvloop 运行事件循环,然后异步代码失败,因为循环已经在运行。
有什么方法可以从类中的同步方法调用异步方法吗?或者我必须重新考虑代码的结构?
运行时错误的设计正是为了防止您尝试执行的操作。run_until_complete
是一个阻塞调用,在 async def 中使用它会停止外部事件循环。
简单的解决方法是通过实际的异步方法公开所需的功能,例如:
class Resource:
def name(self):
return loop.run_until_complete(self.name_async())
async def name_async(self):
resource = await _get_remote_resource(self.key)
return f"{resource.pk}"
然后在 fastapi 中,您可以以本机方式访问 API:
@app.get("")
async def get(key):
return await Resource(key).name_async()
您还可以定义__str__(self)
回来self.name()
,但最好避免这种情况,因为像这样基本的事情str()
也应该可以从 asyncio 内部调用(由于用于日志记录、调试等)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)