QUERY · ISSUE
asyncio implement cpython all_tasks
enhancement
It would be very useful to have the ability to get a list of all tasks similar to the cpython implementation.
Currently to track all running tasks, tasks must be stored in a global list variable which is not ideal and error prone.
- Would you be willing to sponsor this work? Yes
CANDIDATE · ISSUE
Asyncio task scheduling issue when using run_until_completed
bug
Port, board and/or hardware
any port with asyncio support
MicroPython version
micropython-1.25.0 running on win32 [MSC v.1916 64 bit]
Reproduction
The issue is linked to the fact that run_until_complete does not complete the processing of the awaited task before returning to hte caller. If other pending tasks are waiting it, they will be lost forever.
The code below will reproduce the issue.
- When the tasks are await-ed form an async function, everything works as expected (function
async_test) - When the tasks are started from a sync function using run_until_complete, scheduling is broken (function
sync_test)
This issue is specific to micropython asyncio implementation ofrun_until_completeand does not occur in CPython.
import sys, asyncio, random
def get_event_loop():
if sys.implementation.name == "micropython":
return asyncio.get_event_loop()
else:
try:
eventloop = asyncio.get_running_loop()
except RuntimeError:
eventloop = asyncio.new_event_loop()
return eventloop
class Worker:
def __init__(self):
self._eventLoop = None
self._tasks = []
def launchTask(self, asyncJob):
if self._eventLoop is None:
self._eventLoop = get_event_loop()
return self._eventLoop.create_task(asyncJob)
async def job(self, prerequisite, taskName):
if prerequisite:
await prerequisite
await asyncio.sleep(2)
print(taskName, "work completed")
def planTasks(self):
self._tasks.append(self.launchTask(self.job(None, 'task0')))
self._tasks.append(self.launchTask(self.job(self._tasks[0], 'task1')))
self._tasks.append(self.launchTask(self.job(self._tasks[1], 'task2')))
async def waitForTask(self, taskIdx):
return await self._tasks[taskIdx]
def syncWaitForTask(self, taskIdx):
return self._eventLoop.run_until_complete(self._tasks[taskIdx])
async def async_test():
print("--- Running the async test")
worker = Worker()
worker.planTasks()
await worker.waitForTask(0)
print("-> task0 done")
await worker.waitForTask(2)
print("-> task2 done")
def sync_test():
print("--- Running the sync test")
worker = Worker()
worker.planTasks()
worker.syncWaitForTask(0)
print("-> task0 done")
worker.syncWaitForTask(2)
print("-> task2 done")
asyncio.run(async_test())
sync_test()
Expected behaviour
--- Running the async test
task0 work completed
-> task0 done
task1 work completed
task2 work completed
-> task2 done
--- Running the sync test
task0 work completed
-> task0 done
task1 work completed
task2 work completed
-> task2 done
Observed behaviour
--- Running the async test
task0 work completed
-> task0 done
task1 work completed
task2 work completed
-> task2 done
--- Running the sync test
task0 work completed
-> task0 done
-> task2 done
Additional Information
I will submit a pull request with a suggested fix
Code of Conduct
Yes, I agree