Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:当已经有一个事件循环在运行时,从同步方法调用异步代码_Python_Asynchronous_Python Asyncio_Fastapi - Fatal编程技术网

Python:当已经有一个事件循环在运行时,从同步方法调用异步代码

Python:当已经有一个事件循环在运行时,从同步方法调用异步代码,python,asynchronous,python-asyncio,fastapi,Python,Asynchronous,Python Asyncio,Fastapi,我正在使用FastAPI和uvloop以高效的方式为RESTAPI提供服务 我有很多异步代码可以调用远程资源,如数据库、存储器等,这些函数如下所示: async def\u get\u remote\u资源(key:str)->资源: #做一些异步工作 返回资源 我正在实现一个现有抽象基类的接口,我需要在同步方法中使用上面的异步函数。我做过类似的事情: 类资源: 定义(自我): resource=asyncio.run_直到_完成(_get_remote_resource(self.key))

我正在使用FastAPI和uvloop以高效的方式为RESTAPI提供服务

我有很多异步代码可以调用远程资源,如数据库、存储器等,这些函数如下所示:

async def\u get\u remote\u资源(key:str)->资源:
#做一些异步工作
返回资源
我正在实现一个现有抽象基类的接口,我需要在同步方法中使用上面的异步函数。我做过类似的事情:

类资源:
定义(自我):
resource=asyncio.run_直到_完成(_get_remote_resource(self.key))
返回f“{resource.pk}”
太好了!现在,我在fastapi中创建了一个端点,以使这项工作可访问:

@app.get(“”)
异步def get(密钥):
返回str(资源(键))
问题是FastAPI已经使用uvloop获取并运行事件循环,然后异步代码失败,因为循环已经在运行


有没有办法从类中的同步方法调用异步方法?或者我必须重新考虑代码的结构吗?

运行时错误的设计正是为了阻止您尝试执行的操作
run_,直到_complete
是一个阻塞调用,在异步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()

您也可以定义
\uu str\uuuuuuuuuuuuuuself(self)
来返回
self.name()
,但这是最好避免的,因为像
str()
这样的基本内容也应该可以从asyncio内部调用(由于在日志记录、调试等中使用)。

我想补充@user4815162342的答案

FastAPI
是一个不同步的框架。我建议坚持几个原则:

  • 不要以阻塞方式在同步函数中执行IO操作。异步准备此资源,并已将准备好的数据传递给同步函数(这一原则可以称为同步代码的异步依赖项)
  • 如果您仍然需要在同步代码中执行阻塞IO操作,请在单独的线程中执行。并通过
    asyncio
    def
    端点,
    run_in_executor
    ThreadPoolExecutor
    def
    后台任务)异步等待该结果
  • 如果需要执行阻塞CPU绑定的操作,则将其执行委托给单独的进程(最简单的方法是使用
    ProcessPoolExecutor
    或任何任务队列运行\u in\u executor)

是的,我同意直截了当的解决方案是使用异步方法,但是,类资源实际上是抽象基类的实现,因此这些方法已经定义。@NicolasMartinez这是新信息。我认为这样的设计是行不通的——你需要切换到一个异步感知的ABC。是的,我忘了在问题中包括这个!尽快编辑。谢谢你的帮助。第二个项目符号中的“同步代码”应该是“异步代码”吗?所谓同步代码,我指的是一段不包含异步调用,但包含准备操作和对同步阻塞函数的调用的代码。