Description
When using asyncio
in MicroPython, the event loop implementation (asyncio.run
) ends up polling Python objects in a queue. The polling code does this (extmod/modselect.c:poll_poll_internal
):
...
mp_uint_t start_tick = mp_hal_ticks_ms();
mp_uint_t n_ready;
for (;;) {
// poll the objects
n_ready = poll_map_poll(&self->poll_map, NULL);
if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) {
break;
}
MICROPY_EVENT_POLL_HOOK
}
...
The for(;;)
loop above is a busy wait loop. In the Zephyr port, it consumes a lot of CPU time and it starves other threads. Even when MICROPY_EVENT_POOL_HOOK
is set to k_yield
(and thus the loop gives control back to the OS scheduler after each iteration) the code will still take most of the CPU time. Setting MICROPY_EVENT_POOL_HOOK
to something like k_msleep(100)
(which waits 100ms before running another iteration of the loop) fixes the starving issue, but it delays the Python thread for no good reason.
I have a possible solution for this, but please let me know first if there is interest to move this forward, since lately I got the impression that the Zephyr port isn't exactly a "fist class citizen" in the world of MicroPython ports.