【问题标题】:Sync code to async, without rewriting the function将代码同步到异步,无需重写函数
【发布时间】:2020-09-30 15:57:46
【问题描述】:

基本上我有类似这样的同步代码:

def f(.):
   ...
def call(.):
   ..Some sync code..
   try:
      resp = f(..)
      ...some more transformations of resp...
          return ..
   except:
      ..Some error handling..

async def af(.):
    ...

基本上我想动态更改call 的代码,以便它可以调用和等待af 函数而不是f。有没有解决的办法?我在 github 上找到了syncit,但这似乎不是我的解决方案,因为您必须先将代码重写为异步,然后再将其降级为同步。任何帮助将不胜感激。

【问题讨论】:

标签: python python-asyncio


【解决方案1】:

asyncio 世界中,每个协程都可以在其他协程内部(使用await)或通过事件循环阻塞调用(使用run_until_complete())执行。

您不能在常规函数中等待协程,因为此函数的调用会阻塞,而要等待的协程需要阻​​塞事件循环执行。这就是 asyncio 设计的工作方式。

如果您认为您的call() 函数被阻塞并且可以访问f() 实现,您可以在f() 运行事件循环中执行协程:

async def af(.):
    ...

def f(.):
   loop = asyncio.get_event_loop()
   return loop.run_until_complete(af())

def call(.):
   ..Some sync code..
   try:
      resp = f(..)
      ...some more transformations of resp...
          return ..
   except:
      ..Some error handling..

如果您无权访问 f() 实现,我认为您无法更改 call() 以等待协程(没有一些丑陋的猴子补丁)。

我认为将call() 重写为异步将是唯一的好选择。

【讨论】:

    【解决方案2】:

    这里有两个混合同步和异步代码的选项。

    给定

    import asyncio
    
    import trio
    
    from unsync import unsync
    

    代码

    选项 1 - trio

    给定同步代码 (call),通过 trio (async_div) 调用异步函数:

    # Sync code
    def call(x, y):
        """Return an awaited result."""
        try:
            resp = async_div(x, y)
        except ZeroDivisionError:
            return "Caught an exception."
        return resp
        
    
    # Wrapper
    def async_div(*args):
        """Return results from an async function."""
        return trio.run(_async_div, *args)
    
    
    # Async code
    async def _async_div(x, y):
        """Return an async result."""
        await trio.sleep(3)
        return x / y
    

    选项 2 - unsync

    @unsync装饰异步代码并调用result()

    # Sync code
    def call(x, y):
        """Return an awaited result."""
        try:
            resp = async_div(x, y).result()
        except ZeroDivisionError:
            return "Caught an exception."
        return resp
    
    
    # Async code
    @unsync
    async def async_div(x, y):
        """Return an async result."""
        await asyncio.sleep(3)
        return x / y
    

    演示

    在规定的延迟(3秒)之后,结果是一样的:

    call(0, 1)
    # 0.0
    
    call(1, 0)
    # 'Caught an exception.'
    

    另见

    一些额外的资源:

    【讨论】:

      猜你喜欢
      • 2022-10-14
      • 2012-10-22
      • 2018-07-06
      • 1970-01-01
      • 2017-05-19
      • 2021-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多