Fix the `await_ready` polling rate by exarkun · Pull Request #415 · gridsync/gridsync
Fixes #414
This brings CPU usage all the way down to 30% - comparable to where pulseaudio or Firefox idles :( I guess that's what passes for industry standard now.
Maybe at some future point we can actually get rid of polling to address this the rest of the way.
Turns out we can use a fake clock fairly easily here, and we have to *something* because we get a Mock which doesn't work at all otherwise.
Thanks a lot for this clever solution. Even as a temporary fix, this is a big improvement over the previous behavior (and I got to learn about MemoryReactorClock.pump -- cool!).
One thing I noticed here (and please correct me if I'm misunderstanding) is that the result of Poller.target isn't actually being propagated up to the waiting Deferred (and, likewise, your Failure isn't wrapping the exception) resulting in those details being swallowed. Given the currently-very-narrow/singular usage of Poll, however, this isn't a big deal -- and is certainly not worth holding anything up.
Merging now... Thanks again!
Thanks a lot for this clever solution. Even as a temporary fix, this is a big improvement over the previous behavior (and I got to learn about
MemoryReactorClock.pump-- cool!).One thing I noticed here (and please correct me if I'm misunderstanding) is that the result of
Poller.targetisn't actually being propagated up to thewaitingDeferred (and, likewise, yourFailureisn't wrapping the exception) resulting in those details being swallowed.
Hm. I didn't test that case so we should assume it is broken. :) However, considering this code from Poller:
try:
ready = yield self.target()
if ready:
self._completed()
else:
self._schedule()
except Exception: # pylint: disable=broad-except
self._deliver_result(Failure())
that propagation is exactly the intent. If self.target() fails then the except Exception: block should execute. Failure() (called with no arguments like that) captures the "current exception state" to initialize the Failure instance. Then _deliver_result will send it to all waiting Deferreds. It does so with Deferred.callback but that is equivalent to Deferred.errback when called with a Failure.
There's plenty of places things could go wrong there so I should have tested it...
exarkun
deleted the
414.await_ready-rate-limit
branch
Failure()(called with no arguments like that) captures the "current exception state" to initialize the Failure instance.
Ooh... I did not know that a Failure() would bubble everything up like that (and assumed that, given the python mantra of "explicit is better than implicit", the outer exception object would naturally have to be passed in). Then again, I typically use inlineCallbacks with traditional exceptions over the callback/errback methods... Anyway, good to know! Thank you for explaining. :)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters