dabeaz / curio

Good Curio!
Other
4.01k stars 240 forks source link

Suspend after setting event #293

Closed brcharron closed 5 years ago

brcharron commented 5 years ago

Hello, I am just starting with curio, loving it so far but I have found some unexpected behavior with events (curio 0.9, python 3.7.3). In the following code I have two "waiters" setting an event each in a queue and a "setter" getting them from the queue and setting them.

import curio
q = curio.Queue()

async def waiter(value):
    evt = curio.Event()
    evt.value = value
    await q.put(evt)
    await evt.wait()
    print('processing', value)

async def setter():
    async for evt in q:
        print('setting', evt.value)
        await evt.set()
        await q.task_done()

async def main():
    w1 = await curio.spawn(waiter, 1)
    w2 = await curio.spawn(waiter, 2)
    s = await curio.spawn(setter)
    await w1.join()
    await w2.join()
    await s.cancel()

curio.run(main)

The output is

setting 1
setting 2
processing 1
processing 2

although I would have expected

setting 1
processing 1
setting 2
processing 2

namely, that the "waiter" processing the event during the await evt.set() of the "setter". If this is the expected behavior, how would I get the one I am looking for?

imrn commented 5 years ago

Once setter task starts running there is nothing to make it pause at any async point if prerequisites for continuous execution is satisfied. So you get that output.

dabeaz commented 5 years ago

The default behavior of Curio is to never task-switch unless a blocking operation is performed. set() doesn't normally block so you're not going to see a task switch take place at that point.

This is something that can be changed though. If you want to force a task switch, you could insert an await curio.schedule() call after the await evt.set(). If you wanted to hide this detail, you could also inherit from Event and redefine the set() method to include the additional curio.schedule() call.

brcharron commented 5 years ago

Thanks a lot for the explanation and implementation suggestion, it works exactly as desired. It seems that curio.schedule() is not documented but given its one line implementation I guess I could have come up with it if I was more familiar with the concepts...