Являются ли asyncio.Event wait'ers гарантированно уведомленными о наступающем событии? - PullRequest
0 голосов
/ 06 ноября 2019

Ожидает ли сопрограмма ожидающего установки asyncio.Event уведомления каждый раз, когда устанавливается событие?

Ни Event.set (), ни Event.clear () не являются ожидаемыми. Таким образом, событие может быть установлено и очищено без возврата управления в цикл. Таким образом, я полагаю, что вызов set () и clear () не оповестит официантов о событии. Единственный способ убедиться, что официанты уведомлены, - добавить asycnio.sleep (0), чтобы принудительно вернуть элемент управления в цикл между set () и clear (). Но для меня это выглядит довольно некрасиво.

Вот пример:

NUM_EVENTS = 1000
NUM_WAITERS = 1000

import asyncio

async def waiter(event, id):
    print('waiting for it ...')
    for i in range(NUM_EVENTS):
        await event.wait()
        await asyncio.sleep(0)  # might be dropped by affects order
        print(f'... {id} got {i}')

async def main():
    # Create an Event object.
    event = asyncio.Event()

    # Spawn a Task to wait until 'event' is set.
    waiter_tasks = []
    for i in range(NUM_WAITERS):
        waiter_tasks.append(asyncio.create_task(waiter(event, i)))

    # Sleep for 1 second and set the event.
    await asyncio.sleep(1)
    for i in range(NUM_EVENTS):
        event.set()
        await asyncio.sleep(0)  # leaving this out will result in the waiters only receiving the event once
        event.clear()

    # Wait until the waiter task is finished.
    await asyncio.wait(waiter_tasks)

if __name__ == '__main__':
    asyncio.run(main())

Если пропустить asyncio.sleep(0) в строке 31, официанты получат событие только один раз (вместо 1000) раз.

Но как сделать это чисто?

1 Ответ

0 голосов
/ 06 ноября 2019

Ожидает ли сопрограмма установки asyncio.Event, которое будет гарантированно уведомляться каждый раз при установке события?

Официант гарантированно только заметит, что set()произошло, пока оно ожидало, даже если за ним сразу следовал clear(). Нет никакой гарантии, что оно будет активировано столько раз, сколько состояние было изменено с ложного на истинное.

Эта более сильная гарантия потребует дополнительного счетчика на объекте, который больше не будет простым логическим значением "мероприятие". Это также было бы несовместимо с threading.Event, что не обеспечивает его.

Но как сделать это чисто?

Чистый способ был бы для Event только для того, чтобы отметить, что «что-то» произошло, и что метаинформация , что произошло (включая счетчик, если необходимо), хранится рядом. Таким образом, объект события выполняет одну цель: сигнализировать официантам о том, что произошло событие, которого они ждали, и они могут сами выполнить необходимое количество циклов.

Если официантам нужно реагировать наset() немедленно , тогда ожидание asyncio.sleep(0) - это путь, но в Asyncio это отчасти запах дизайна. Трудно сказать, как это исправить, не зная больше о вашем коде.

...