Switching between tasks

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
User avatar
Ventran
Posts: 19
Joined: Sun Jun 21, 2020 4:28 pm
Location: Poland, Europe

Switching between tasks

Post by Ventran » Tue Oct 27, 2020 9:46 pm

Hello,
I have a questions. It it possible in micropython create e.g three tasks (include forever loop each) and switching between them.

This is a graph what i need to do:
what-i-need-to-do.png
what-i-need-to-do.png (12.59 KiB) Viewed 227 times
I trying this but not work properly:

Code: Select all

async def task1():
    while True:
	todo()
        await asyncio.sleep_ms(500)

async def task2():
    while True:
	todo()
        utime.sleep_ms(2000)
        await asyncio.sleep_ms(5000)

async def task3():
    while True:
	todo()
        utime.sleep_ms(1500)
        await asyncio.sleep_ms(10000)

Code: Select all

loop = asyncio.get_event_loop()
loop.create_task(task1())
loop.create_task(task2())
loop.create_task(task3())
loop.run_forever()

User avatar
jimmo
Posts: 2015
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Switching between tasks

Post by jimmo » Wed Oct 28, 2020 12:47 am

Yes what you're doing looks right except for the "utime.sleep_ms" -- you cannot use a blocking sleep in asyncio code. But you don't need it, the "await asyncio.sleep_ms" should be all you need.

So your diagram says you have three tasks that do something every 5, 5, and 2 seconds respectively.

This program does what I'd expect (see output below). However the thing to remember is that if whatever the "todo()" task is is blocking, then it will prevent other tasks from running, so todo() itself likely needs to be async. Also if todo() takes some time to run, then the sleep time probably needs to be adjusted.

Code: Select all

import time
import uasyncio as asyncio

start_ms = time.ticks_ms()

async def task1():
    while True:
        print(time.ticks_diff(time.ticks_ms(), start_ms), "task 1")
        await asyncio.sleep_ms(5000)

async def task2():
    while True:
        print(time.ticks_diff(time.ticks_ms(), start_ms), "task 2")
        await asyncio.sleep_ms(5000)

async def task3():
    while True:
        print(time.ticks_diff(time.ticks_ms(), start_ms), "task 3")
        await asyncio.sleep_ms(2000)

loop = asyncio.get_event_loop()
loop.create_task(task1())
loop.create_task(task2())
loop.create_task(task3())
loop.run_forever()

Output:

Code: Select all

0 task 1
0 task 2
0 task 3
2002 task 3
4005 task 3
5001 task 1
5001 task 2
6006 task 3
8007 task 3
10003 task 1
10003 task 2
10007 task 3
12009 task 3
14011 task 3
15003 task 1
15003 task 2
16012 task 3
18015 task 3
20003 task 1

User avatar
Ventran
Posts: 19
Joined: Sun Jun 21, 2020 4:28 pm
Location: Poland, Europe

Re: Switching between tasks

Post by Ventran » Wed Oct 28, 2020 8:26 am

OK, I use only:

Code: Select all

await asyncio.sleep_ms( )
but the Display show only Task #3 (5 sec) and Task #2 (1 sec).

Image

I want show on display Task #1 (during 5 sec.), Task #2 (during 5 sec.) and Task #3 (during 2 sec.)

User avatar
jimmo
Posts: 2015
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Switching between tasks

Post by jimmo » Wed Oct 28, 2020 8:29 am

Can you clarify what you mean...

do you want task 1 for some time. THEN task 2 for some time. THEN task 3? in which case they don't need to be separate tasks

What your code does is run the tasks concurrently - i.e. they're all sleeping at the same time, and if they sleep for the same amount of time then they'll end up updating the display at the same time.

User avatar
Ventran
Posts: 19
Joined: Sun Jun 21, 2020 4:28 pm
Location: Poland, Europe

Re: Switching between tasks

Post by Ventran » Wed Oct 28, 2020 11:59 am

jimmo wrote:
Wed Oct 28, 2020 8:29 am
do you want task 1 for some time. THEN task 2 for some time. THEN task 3? in which case they don't need to be separate tasks
Yes.

I want something like this:

Code: Select all

while True:
    display.text("Task #1", 5, 5)
    display.show()
    utime.sleep_ms(5000)
    display.fill(0)

    display.text("Task #2", 5, 5)
    display.show()
    utime.sleep_ms(5000)
    display.fill(0) 

    display.text("Task #3", 5, 5)
    display.show()
    utime.sleep_ms(2000)
    display.fill(0)  
but how I can update content in "reall-time" on the display when show e.g Task #1 ?

User avatar
jimmo
Posts: 2015
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Switching between tasks

Post by jimmo » Wed Oct 28, 2020 11:37 pm

Ventran wrote:
Wed Oct 28, 2020 11:59 am
but how I can update content in "reall-time" on the display when show e.g Task #1 ?
Either:
- Don't sleep for the whole 5 seconds at once. Instead loop for the duration of the task with much smaller sleeps until 5 seconds have passed.

Code: Select all

start_time = time.ticks_ms()
while time.ticks_diff(time.ticks_ms(), start_time) < 5000:
  do_more_work()
  update_display()
  # maybe a small sleep
- Run two tasks, one that periodically updates the display (similar to above) and another that does the actual work telling the other task what the current state is.

User avatar
Ventran
Posts: 19
Joined: Sun Jun 21, 2020 4:28 pm
Location: Poland, Europe

Re: Switching between tasks

Post by Ventran » Fri Oct 30, 2020 6:24 pm

Thank you for you solution. Simple state machine resolve problem.

Three task:
- one for update display
- one for get new value
- one for switching tasks

Image

Post Reply