uasyncio fast_io EventLoop option reduces I/O scheduling latency#287
uasyncio fast_io EventLoop option reduces I/O scheduling latency#287peterhinch wants to merge 1 commit intomicropython:masterfrom peterhinch:uasyncio-fast-io-option
Conversation
|
To add to this the I/O latency of the current code is twice as long as might be expected. Assume there are N coros which issue The reason for this is as follows. Assume user coros as per the test script like async def dummy(self):
while True:
await asyncio.sleep(0)
utime.sleep_ms(10) # Emulate time consuming user codeAssume an initial condition where the run queue contains N such coros. Each will be scheduled before the scheduler's So in the next iteration through the run queue the N coros run a second time before the I/O read is re-scheduled. At the time when this takes place each coro has yielded and been put on the run queue. So after the I/O read has been scheduled the run queue contains the N coros recreating the assumed initial condition. This PR does not alter this default behaviour. But when |
|
From my understanding there are two main things going on here: 1) implementing priorities for coros (low and high); 2) pumping the IO poller faster to give high-priority IO a chance to schedule itself faster. For part 1): would it be simpler to just push the callback to the head of the runq, rather than having a separate queue? Also, it seems the way to specify that the coro has priority here is to make it yield IOReadDone/IOWriteDone (via the appropriate StreamReader/StreamWriter class). Might there not be a more general way to specify that a coro is higher priority, like registering itself as high-prio with the event loop? |
|
My initial plan was indeed to push the coro to the head of The inner loop runs only those tasks which were on The forthcoming fix for the read/write class bug means that the I/O coros register themselves as high priority by ._call_io which places them on I'm unsure what you're suggesting regarding a more general solution. |
This PR offers a solution to the issue discussed in MicroPython issue 2664 and provides a way of accessing the full capability of MicroPython PR 3836; namely the ability to support user-written stream I/O drivers with low latency.
An optional
ioq_len=0arg toget_event_loop()is added. The default behaviour is unchanged from standard: if I/O is pending in the presence of coros on the run queue, the I/O task is appended to the run queue and is scheduled after all pending tasks have yielded.If
ioq_lenis > 0, pending I/O tasks will be scheduled in preference to tasks on the run queue, substantially reducing latency. This reduces the need for buffering of fast I/O devices and improves the response time of user-written I/O drivers.A test program demonstrating this effect may be found here.