[Python-ideas] Tulip / PEP 3156 event loop implementation question: CPU vs. I/O starvation (original) (raw)
Stefan Behnel stefan_ml at behnel.de
Sat Jan 12 07:39:42 CET 2013
- Previous message: [Python-ideas] Tulip / PEP 3156 event loop implementation question: CPU vs. I/O starvation
- Next message: [Python-ideas] Tulip / PEP 3156 event loop implementation question: CPU vs. I/O starvation
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Jan Kaliszewski, 12.01.2013 02:28:
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/unixevents.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.geteventloop().callsoon(hogger) Because callsoon() appends the handler to the ready queue, the while loop will never finish. There is a simple enough solution (Tornado uses this AFAIK): nowready = list(ready) ready.clear() for handler in nowready: 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: #
suggestediterlimitis the parameter actuallimit = max(len(ready), suggestediterlimit) for i in range(actuallimit): if not ready: break handler = ready.popleft() call handler...
Yep, it could simply use itertools.islice() when iterating over _ready with an appropriate upper bound factor relative to the actual length, and then cut down the list after the loop. So it would never go, say, 50% over the initially anticipated workload. Or rather a fixed number, I guess, to make it more predictable for users. That would be a user configurable parameter to the I/O loop.
actual_limit = len(_ready) + max_additional_load_per_loop
for handler in itertools.islice(_ready, None, actual_limit):
call handler...
del _ready[:actual_limit]Stefan
- Previous message: [Python-ideas] Tulip / PEP 3156 event loop implementation question: CPU vs. I/O starvation
- Next message: [Python-ideas] Tulip / PEP 3156 event loop implementation question: CPU vs. I/O starvation
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]