Instead of using single priority queue for all tasks, split into using
"run queue", which represents tasks not waiting until specific time,
which should be run on every (well, next) loop iteration, and wait queue,
still a priority queue. Run queue is a simple FIFO, implemented by
ucollections.deque, recently introduced in pfalcon/micropython. Thus,
there's minimal storage overhead and intrinsic scheduling fairness.
Generally, run queue should hold both a callback/coro and its arguments,
but as we don't feed any send args into coros still, it's optimized to
hold just 1 items for coros, while 2 for callbacks.
Introducing run queue will also allow to get rid of tie-breaking counter
in utimeq implementation, which was introduced to enforce fair scheduling.
It's no longer needed, as all tasks which should be run at given time
are batch-removed from wait queue and batch-inserted into run queue. So,
they may be executed not in the order scheduled (due to non-stable order
of heap), but the whole batch will be executed "atomically", and any new
schedulings from will be processed no earlier than next loop iteration.
This is convenient when components need only to parse a subset of an
application's arguments, and can be implemented with minor changes to
_parse_args: basically just add unknown arguments to a list instead of
raising an exception.
During development, following questions were posed, and subsequently,
answered:
Q #1: Should this be in uasyncio package at all? Upstream doesn't have
this. Pro: will be easier for people do discover (see e.g.
https://github.com/micropython/micropython-lib/issues/148)
A: uasyncio diverges more and more from asyncio, so if something is
convinient for uasyncio, there's no need to look back at asyncio.
Q #2: This provides implements 2 ways to create a WS connections:
1) using start_ws_server(); 2) using wrapping existing StreamReader
and StreamWriter. History: initial prototype of course used 2). But
the idea was "it should be like the official start_server()!!1". But
then I though how to integrate it e.g. with Picoweb, and became clear
that 2) is the most flixble way. So, 1) is intended to be removed.
A: 1) was removed and is not part of the merged version of the patch.
Q #3: Uses native websocket module for read path, but has own
write path due to https://github.com/micropython/micropython/issues/3396
A: So far, so good.
Q #4: Requires https://github.com/micropython/micropython-lib/pull/227
due to https://github.com/micropython/micropython/issues/3394 .
A: The prerequisite was merged.
To use address as returned by getaddrinfo(), we should create a socket
compatible with address family, etc., returned by the same call alongside
the address itself.
To use address as returned by getaddrinfo(), we should create a socket
compatible with address family, etc., returned by the same call alongside
the address itself.
To use address as returned by getaddrinfo(), we should create a socket
compatible with address family, etc., returned by the same call alongside
the address itself.