Рубрики
Без рубрики

Планирование вызовов обычных функций

Автор оригинала: Doug Hellmann.

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

Планирование обратного вызова “Скоро”

Если время обратного вызова не имеет значения, можно использовать call_soon () для планирования вызова для следующей итерации цикла. Любые дополнительные позиционные аргументы после функции передаются обратному вызову при ее вызове. Чтобы передать аргументы ключевого слова в обратный вызов, используйте partial () из модуля functools.

asyncio_call_soon.py

import asyncio
import functools


def callback(arg, *, kwarg'default'):
    print('callback invoked with {} and {}'.format(arg, kwarg))


async def main(loop):
    print('registering callbacks')
    loop.call_soon(callback, 1)
    wrapped  functools.partial(callback, kwarg'not default')
    loop.call_soon(wrapped, 2)

    await asyncio.sleep(0.1)


event_loop  asyncio.get_event_loop()
try:
    print('entering event loop')
    event_loop.run_until_complete(main(event_loop))
finally:
    print('closing event loop')
    event_loop.close()

Обратные вызовы вызываются в том порядке, в котором они запланированы.

$ python3 asyncio_call_soon.py

entering event loop
registering callbacks
callback invoked with 1 and default
callback invoked with 2 and not default
closing event loop

Планирование обратного вызова с задержкой

Чтобы отложить обратный вызов на некоторое время в будущем, используйте call_later () . Первый аргумент – это задержка в секундах, а второй аргумент – это обратный вызов.

asyncio_call_later.py

import asyncio


def callback(n):
    print('callback {} invoked'.format(n))


async def main(loop):
    print('registering callbacks')
    loop.call_later(0.2, callback, 1)
    loop.call_later(0.1, callback, 2)
    loop.call_soon(callback, 3)

    await asyncio.sleep(0.4)


event_loop  asyncio.get_event_loop()
try:
    print('entering event loop')
    event_loop.run_until_complete(main(event_loop))
finally:
    print('closing event loop')
    event_loop.close()

В этом примере одна и та же функция обратного вызова запланирована несколько раз с разными аргументами. Последний экземпляр, использующий call_soon () , приводит к тому, что обратный вызов вызывается с аргументом 3 перед любым из запланированных по времени экземпляров, показывая, что “скоро” обычно подразумевает минимальная задержка.

$ python3 asyncio_call_later.py

entering event loop
registering callbacks
callback 3 invoked
callback 2 invoked
callback 1 invoked
closing event loop

Планирование обратного вызова на определенное время

Также можно запланировать вызов в определенное время. В цикле используются монотонные часы, а не настенные часы, чтобы значение «сейчас» никогда не регрессировало. Чтобы выбрать время для запланированного обратного вызова, необходимо начать с внутреннего состояния этих часов, используя метод цикла time () .

asyncio_call_at.py

import asyncio
import time


def callback(n, loop):
    print('callback {} invoked at {}'.format(n, loop.time()))


async def main(loop):
    now  loop.time()
    print('clock time: {}'.format(time.time()))
    print('loop  time: {}'.format(now))

    print('registering callbacks')
    loop.call_at(now + 0.2, callback, 1, loop)
    loop.call_at(now + 0.1, callback, 2, loop)
    loop.call_soon(callback, 3, loop)

    await asyncio.sleep(1)


event_loop  asyncio.get_event_loop()
try:
    print('entering event loop')
    event_loop.run_until_complete(main(event_loop))
finally:
    print('closing event loop')
    event_loop.close()

Обратите внимание, что время в соответствии с циклом не соответствует значению, возвращаемому time.time () .

$ python3 asyncio_call_at.py

entering event loop
clock time: 1521404411.833459
loop  time: 715855.398664185
registering callbacks
callback 3 invoked at 715855.398744743
callback 2 invoked at 715855.503897727
callback 1 invoked at 715855.601119414
closing event loop