[Python-ideas] Tulip / PEP 3156 event loop implementation question: CPU vs. I/O starvation
Jan Kaliszewski
zuo at chopin.edu.pl
Sat Jan 12 02:28:25 CET 2013
12.01.2013 00:41, Guido van Rossum wrote:
> Here's an interesting puzzle. Check out the core of Tulip's event
> loop:
> http://code.google.com/p/tulip/source/browse/tulip/unix_events.py#672
>
> Specifically this does something like this:
>
> 1. poll for I/O, appending any ready handlers to the _ready queue
>
> 2. append any handlers scheduled for a time <= now to the _ready
> queue
>
> 3. while _ready:
> handler = _ready.popleft()
> call handler
>
> It is the latter loop that causes me some concern. In theory it is
> possible for a bad callback to make this loop never finish, as
> follows:
>
> def hogger():
> tulip.get_event_loop().call_soon(hogger)
>
> Because call_soon() appends the handler to the _ready queue, the
> while
> loop will never finish.
>
> There is a simple enough solution (Tornado uses this AFAIK):
>
> now_ready = list(_ready)
> _ready.clear()
> for handler in now_ready:
> call handler
>
> However this implies that we go back to the I/O polling code more
> frequently. While the I/O polling code sets the timeout to zero when
> there's anything in the _ready queue, so it won't block, it still
> isn't free; it's an expensive system call that we'd like to put off
> until we have nothing better to do.
[...]
> So what's more important? Avoid I/O starvation at all cost or make
> the
> callbacks-posting-callbacks pattern efficient? I can see several
> outcomes of this discussion: we could end up deciding that one or the
> other strategy is always best; we could also leave it up to the
> implementation (but then I still would want guidance for what to do
> in
> Tulip); we could even decide this is so important that the user needs
> to be able to control the policy here
[...]
Maybe it could be, at least for the standard Tulip implementation,
parameterizable with a simple integer value -- the suggested max number
of loop iterations?
E.g. something like the following:
# `suggested_iter_limit` is the parameter
actual_limit = max(len(_ready), suggested_iter_limit)
for i in range(actual_limit):
if not _ready:
break
handler = _ready.popleft()
call handler...
Regards.
*j
More information about the Python-ideas
mailing list