peterhinch / micropython-async

Application of uasyncio to hardware interfaces. Tutorial and code.
MIT License
744 stars 169 forks source link

Queue task_done/join enhancement #108

Closed stephanelsmith closed 1 year ago

stephanelsmith commented 1 year ago

Hello @peterhinch,

In my project, I've found itility in the task_done/join feature in Queue: https://docs.python.org/3/library/asyncio-queue.html

I have something like:

    def _put(self, val):
        self._jncnt += 1
        self._evput.set()  # Schedule tasks waiting on put
        self._evput.clear()
        self._queue.append(val)

    def task_done(self):
        self._jncnt -= 1
        if self._jncnt <= 0:
            self._jnevt.set()
        else:
            self._jnevt.clear()

    async def join(self):
        await self._jnevt.wait()

If there's interest, happy to create a PR for this.

stephanelsmith commented 1 year ago

Related but seperate, my original implementation idea was semaphore like, essentially acquiring (incrementing) on each put, and then releasing on task_done. I had an issue with it, essentially, my program was exiting on event.wait().... Is it just me or have you seen this?

I would expect this to hang. On Python3 it does, but on micropython it exits without message on both unix and esp32 ports.

import asyncio
from asyncio import Event

async def main():
    print('start')
    event = Event()
    await event.wait()
    print('done')

asyncio.run(main())

I see the same thing if I add wait before event is set, like this, but the wait could be in the waiter as well.

async def main():
    event = Event()
    asyncio.create_task(waiter(event))
    await event.wait()  # Pause here until event is set
    await asyncio.sleep(2)
    print('Setting event')
peterhinch commented 1 year ago

Re Queue methods I would be interested in a PR, ideally with asyntest.py adapted to test these methods.

I agree the first example should hang and can confirm that it doesn't. I'm not clear about the second example - what is the waiter task? In any event the first warrants raising an issue in my opinion.

stephanelsmith commented 1 year ago

I'll put together a PR with associated test, no problem.

For the second example, what I did not mention and should have is that is reproducable using the Event example from the documentation as a starting point. A little more 'in application' I guess. https://github.com/peterhinch/micropython-async/blob/master/v3/docs/TUTORIAL.md#32-event

The initial example is probably better for raisining an issue.