Синхронизировать код с асинхронным без переписывания функции - PullRequest
0 голосов
/ 01 июля 2018

В основном у меня есть синхронный код, похожий на этот:

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. Это можно обойти? Я нашел syncit на github, но мне кажется, что это не решение проблемы, так как сначала нужно переписать код для асинхронизации, а затем понизить его до синхронизации. Любая помощь будет оценена.

Ответы [ 2 ]

0 голосов
/ 02 июля 2018

Здесь я изменил ваш пример в рабочую демонстрацию с использованием библиотеки 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 документы и это Talk Python интервью с создателем Н. Смитом для получения дополнительной информации и его философии асинхронного программирования.

0 голосов
/ 02 июля 2018

В asyncio мире каждая сопрограмма может быть выполнена либо внутри другой сопрограммы (с использованием await), либо с помощью вызова блокировки цикла событий (с использованием run_until_complete()).

Вы не можете ожидать сопрограммы внутри обычной функции, так как вызов этой функции будет блокировать, в то время как ожидание сопрограммы требует блокировки выполнения цикла события. Вот как asyncio предназначен для работы.

Если вы согласны с представлением о блокировке вашей call() функции и имеете доступ к реализации f(), вы можете выполнить сопрограмму внутри f() цикла событий runnning:

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() в асинхронный режим будет только хорошим вариантом.

...