将代码同步为异步,而无需重写功能

时间:2018-07-01 19:48:34

标签: python python-asyncio

基本上,我有与此类似的同步代码:

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,但对我来说这并不是一个解决方案,因为您必须先重新编写代码以进行异步处理,然后再降级以进行同步。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分: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()重写为异步是唯一的好选择。

答案 1 :(得分:0)

在这里,我已经使用trio库将您的示例修改为可以正常运行的演示:

给出

# Sync code
def call(x, y):
    """Return an awaited result."""
    try:
        resp = f(x, y)
        return resp
    except ZeroDivisionError:
        return "Caught an exception."


# Async code
async def af(x, y):
    """Return an async result."""
    await trio.sleep(3)
    return x / y

代码

def f(*args):
    """Return results from an async function."""
    return trio.run(af, *args)

演示

call(0, 1)
# 0.0

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

给出同步代码call,您可以在函数trio中使用f来调用异步函数。

另请参阅trio docs和创建者N. Smith的Talk Python interview,以了解更多详细信息及其异步编程哲学。