uasyncio : Cancelling a task

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
User avatar
cemox
Posts: 32
Joined: Mon Oct 08, 2018 5:31 pm
Location: Turkey

uasyncio : Cancelling a task

Post by cemox » Sat May 02, 2020 7:15 am

I am trying to cancel a task and start a new one (with new parameters). (Board ESP8266, latest Mciropython from Master Branch in github)

Code: Select all

import uasyncio as asyncio

async def delayN(n):
    while (True):
        print("delay for {} seconds".format(n))
        await asyncio.sleep(n)

async def delay1():
    while (True):
        print("This is  delay1")
        await asyncio.sleep(1)

async def cancelTask(loop):
    await asyncio.sleep(6)
    print("canceling task")
    asyncio.Task(delay1).cancel()
    # asyncio.Task(delay1).cancel()
    # loop.stop()
    loop.create_task(delayN(2))
    await asyncio.sleep(0)
    # loop.run_forever()

loop = asyncio.get_event_loop()
loop.create_task(delay1())
loop.create_task(delayN(3))
loop.create_task(cancelTask(loop))

loop.run_forever()
This works fine in the beginning. But after 6 seconds when cancelTask function is called, I want the program cancel the task for 'delayN(3)' (delaying for 3 seconds) and start a new task 'delayN(2)' (delaying for 2 seconds). The new task is created, but 'delayN(3)' task is not cancelled. How can I achieve that? (Note: uasyncio.cancel() does not exist in the uasyncio module in my version).

User avatar
pythoncoder
Posts: 4472
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: uasyncio : Cancelling a task

Post by pythoncoder » Sat May 02, 2020 7:56 am

You need uasyncio V3. Taks cancellation in V2 is buggy. While there is a workround the simple answer is to ensure you have V3. You can test for V3 by issuing

Code: Select all

import uasyncio as asyncio
print(asyncio.__version__)
Current daily firmware builds should have V3. Then I suggest you look at the V3 tutorial in this repo. This is the sort of thing you need:

Code: Select all

import uasyncio as asyncio

async def delayN(n):
    while (True):
        print("delay for {} seconds".format(n))
        await asyncio.sleep(n)

async def delay1():
    while (True):
        print("This is delay1")
        await asyncio.sleep(1)

async def cancelTask(d1):
    await asyncio.sleep(6)
    print("canceling task")
    d1.cancel()
    asyncio.create_task(delayN(2))

async def main():
    d1 = asyncio.create_task(delay1())
    asyncio.create_task(delayN(3))
    asyncio.create_task(cancelTask(d1))
    await asyncio.sleep(10)

asyncio.run(main())
Peter Hinch

User avatar
cemox
Posts: 32
Joined: Mon Oct 08, 2018 5:31 pm
Location: Turkey

Re: uasyncio : Cancelling a task

Post by cemox » Sat May 02, 2020 9:52 am

Thanks Peter. Actually, what I am trying to do is to change the url of of a connection (web radio).

Code: Select all

async def play(url, port):
    global buff
    global bufferfull
    _, _, host, path = url.split('/', 3)
    print(host, path)
    addr = socket.getaddrinfo(host, port)[0][-1]
    
    reader, writer = await asyncio.open_connection(host, port)

    writer.write(bytes('GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n' % (path, host), 'utf8'))
    await writer.drain()
    
    while (True):
        # await reader.read(256)
        buff = yield from reader.read(256)
        bufferfull = True
        asyncio.sleep(0)
this function is added to to a asyncio loop and the loop is running forever. How can I simply change the url (web radio station) of this connection?

User avatar
pythoncoder
Posts: 4472
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: uasyncio : Cancelling a task

Post by pythoncoder » Sat May 02, 2020 5:24 pm

Can you not cancel the Play task and restart it with a new URL?

The key to task cancellation is to store the task instance returned by .create_task, as in my example above.
Peter Hinch

User avatar
cemox
Posts: 32
Joined: Mon Oct 08, 2018 5:31 pm
Location: Turkey

Re: uasyncio : Cancelling a task

Post by cemox » Sun May 03, 2020 4:29 am

Thanks Peter, I did exactly what you said and it works :). Something like this:

Code: Select all

playTask = asyncio.create_task(play(url1, port1))
and in change_station coro:

Code: Select all

async def changeChannel():
	playTask.cancel()
        playTask = asyncio.create_task(play(url2, port2))

User avatar
pythoncoder
Posts: 4472
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: uasyncio : Cancelling a task

Post by pythoncoder » Sun May 03, 2020 6:31 pm

Looks good :)
Peter Hinch

Post Reply