Вызов сопрограммы без сдачи цикла событий - PullRequest
4 голосов
/ 07 апреля 2019

Я могу разбить код на части для удобства чтения. Так

async coro_top():
  print('top')
  print('1')
  # ... More asyncio code

  print('2')
  # ... More asyncio code

... в нечто вроде

async coro_top():
  print('top')
  await coro_1()
  await coro_2()

async coro_1()
  print('1')
  # ... More asyncio code

async coro_2()
  print('2')
  # ... More asyncio code

Однако дополнительные await означают, что они не являются строго эквивалентными

  • Другая параллельная задача может запускать код в диапазоне от print('top') до print('1'), поэтому повышается вероятность состязания для определенных алгоритмов.

  • Имеются (предположительно) небольшие издержки при создании цикла событий

Так есть ли способ вызова сопрограммы без использования цикла события, чтобы избежать вышеупомянутого?

1 Ответ

3 голосов
/ 07 апреля 2019

Суть вопроса неверна: вопреки ожиданиям людей, await не автоматически поддается циклу событий.Вы можете легко проверить, что:

async def noop():
    pass

async def busy_loop(msg):
    while True:
        print(msg)
        await noop()

# keeps printing 'a', the event loop is stuck
asyncio.get_event_loop().run_until_complete(
    asyncio.gather(busy_loop('a'), busy_loop('b')))

Хотя busy_loop ожидает все время, оно все равно блокирует цикл обработки событий, так что другие задачи не будут выполняться, и даже отмена этого невозможна.Это связано с тем, что сопрограмма noop, которую она ожидает, никогда не приостанавливает выполнение.

await some_coroutine() не означает «расписание some_coroutine() и выход в цикл обработки событий, возобновление после его завершения».Это означает «начать выполнение some_coroutine() и , если / когда он решит приостановить, приостановить вдоль », и предполагая, что первый может привести к ошибкам .

Другими словами, разбитый код действительно эквивалентен коду перед рефакторингом.Единственный способ выполнения другой задачи между print('top') и print('1') заключается в добавлении между ними нового await (тот, который фактически приостанавливает сопрограмму), но то же самое можно сказать и об исходном коде.

Существует (предположительно) небольшие издержки при создании цикла обработки событий

Накладные расходы существуют, но они сопоставимы с накладными расходами при вызове функции, а не сзначительно большие накладные расходы на выполнение итерации цикла событий.

...