-
-
Notifications
You must be signed in to change notification settings - Fork 21
Non-busy loop #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This is in preparation for a non-busy sleep.
Here we just take the simple ('tiny') approach to scheduling the sleep in a thread. A more sophisticated ('not tiny') implementation might be to pass this sleep back to the loop so that the wake event can use it as a timeout.
|
This looks good to me, but I'm worried about the precision of |
|
Got it! Is it specifically If it is the case then I think that might be a hard limiting factor - either we use a busy loop, or we use lower-level primitives like EDIT: FWIW, if there was a desire to support WASM, and if on this platform a polling loop would be considered acceptable - possibly not at 100% CPU but with e.g. |
|
Pyodide allows to run
But wouldn't it block the whole loop during the 0.01s sleeps? |
BTW I don't understand how you would use |
Ah you're right, I'm not thinking this through. We'd end up never blocking on our (EDIT: actually, the sleeping could probably be an appropriately-calculated |
|
I don't know if there would be a way to integrate |
|
Actually, this kind of integration is exactly a use-case I had in mind. It's for this reason that the bulk of our implementation lives in a async def async_run(self, coro):
...
while ...:
self._step(...)
await asyncio.sleep(0)The same pattern should work for any host event loop. That said, implementing this isn't high-priority for me. I'm not a user of any other event loop library (at least I'm not any more!) so it'd be hard for me to do due diligence that it works correctly. Other than that, you might find #8 interesting, which indeed switches sleeping over to use an event timeout rather than a thread. I think that's probably the 'final form' of a non-busy-loop implementation, as it also minimises the number of threads involved. (E.g. no more threads needed for implementing sleeping.) |
…s gracefully. Very much an edge case, but never let it be said that tinyio isn't the most robust solution out there :)
…ly just iterates.
… of the Event. This is in support of potentially allowing timeouts in the future - we now distinguish specifically which _Wait we might be timing out.
94c4b49 to
0bf90a0
Compare
|
Okay, I think I now have enough confidence in this PR to merge it. Rounding out the two discussions above:
|
Okay, this is a major refactor of the internals of the loop. It should no longer busy-poll for whether threads or sleeps have completed.
This is accomplished by (a) promoting
tinyio.Event.waitfrom a regular coroutine to instead be special-cased by the event loop, (b) havingtinyio.Event.setnotify athreading.Eventthat the loop can unblock, and (c) rewriting our variouswhile cond_not_satisfied: yieldoperations into ayield some_event.wait()instead.The extra complexity this implies means that we're now at 262 LOC for the core event loop (
pygount _core.py). This is just about acceptable for our '~200 LOC' claim. Let's see if we need anything more in the future! 😁