mnot/thor — pull request #31 by sebastien (2012-12-23 23:35:18+00:00)
Title: thor.loop.schedule(delay=0) improvement

Hello Mark!

First, thanks a lot for Thor, which it is exactly what I was looking for: a simple, elegant, fast and low-level HTTP library.

I've been working on a Thor-based backend for Retro https://github.com/sebastien/retro and so far I'm very pleased with the results. The only problem that I had so far is how to efficienlty loop without stealing other event handler's CPU time.

Here's some context. Retro applications are WSGI applications: they return an iterator, and sometimes these iterators are very long running. For the sake of this example, we'll imagine that the application's response body iterator is something like:

```
while True: yield str(math.random())
```

In Thor's HTTP servers, events are triggered when there's incoming data (exchange, and then request_{start|body|done}). So I have between 3 and N opportunities to call next() on the iterator: when response_start is triggered, one or more times when response_body is triggered and then one more time when response_done is triggered.

This means that the code I have right now in response_done is like this:

```
def _onRequestDone( self, trailers ):
self._stepUntilEnd()

def _stepUntilEnd( self ):
if self.step():
thor.loop.schedule(0.0, self._stepUntilEnd)

def step( self ):
try:
res = self.iterator.next()
return True
except StopIteration, e:
self.exchange.response_done(self.trailers)
return False
```

The problem, though is that this makes the responses much slower than doing the following

```
def _stepUntilEnd( self ):
while self.step(): pass
```

What I would like to do is to have the same performance as a "while", but without stealing the CPU from the event loop (which means using thor.loop.schedule).

My understanding is that it's because of the default 0.5s precision -- which means that unless there's a lot of events happening, there will be a precision delay between each iteration.

However, I don't want to have a greater precision if it means polling too often (which would negatively impact the CPU).

The idea would then be to allow `schedule()` to directly call a loop step if the event is scheduled before the next iteration.

I've done some tests and managed to update the loop to bypass the precision delay for `schedule(delay=0.0)`. Please Let me know if this OK!