Search code examples
pythonpython-asynciocurio

Issue with waiting for an Event in curio


I'm using curio to implement a mechanism of two tasks that communicate using a curio.Event object. The first task (called action()) runs first, and awaits the event to be set. The second task (called setter()) runs after the first one, and is setting the event.

The code is the following:

import curio

evt = curio.Event()


async def action():
    await evt.wait()
    print('Performing action')


async def setter():
    await evt.set()
    print('Event set')


async def run():
    task = await curio.spawn(action())
    await setter()
    print('Finished run')
    await task.wait()


curio.run(run())

The output is the following:

Event set
Finished run
Performing action

Which means that print('Performing action') is executed AFTER print('Finished run'), and that's what I'm trying to prevent - I was expecting that calling await evt.set() will also invoke all of its waiters, and run() won't continue until all of the waiters were invoked, meaning that action() will be continued BEFORE print('Finished run') is executed. This is the output I would like to have:

Event set
Performing action
Finished run

What am I getting wrong? Is there any way to change this behavior? I would like to have more control over the execution order.

Thanks


Solution

  • Setting Event is a way to signal that something happened: it as you already noted doesn't provide invocation of waiters.

    If you want to report run finished after action performed you should report it after awaiting for action:

    async def run():
        task = await curio.spawn(action())
        await setter()
        await task.wait()  # await action been performed
        print('Finished run')  # and only after that reporting run() is done
    

    If you want to block execution of run() until something happened you can do it with another event wait() that should be set() when this something happend:

    import curio
    
    evt = curio.Event()
    evt2 = curio.Event()
    
    
    async def action():
        await evt.wait()
        print('Performing action')
        await evt2.set()
        print('Event 2 set')
    
    
    async def setter():
        await evt.set()
        print('Event set')
    
    
    async def run():
        task = await curio.spawn(action())
        await setter()    
        await evt2.wait()
        print('Finished run')
        await task.wait()
    
    
    curio.run(run())
    

    Res:

    Event set
    Performing action
    Event 2 set
    Finished run