[Twisted-Python] Re: r15451 - Fix test failures under windows by changing the eventual-send operation to

Brian Warner warner at lothar.com
Sat Dec 31 13:57:21 EST 2005

>> Yes it does: order of method call.

Ah. That's useful to know: I would prefer to use a non-threading-related call
to achieve this eventual-send functionality. I'll add a TODO test to check
that this promise is being met.

> It should be fixable by storing the last time of an element added to the
> queue, and adding epsilon if current time is the same.

Wouldn't you have to guarantee that epsilon is smaller than the resolution of
your time.time() return value? What if you sorted on a tuple of (time,
counter) instead? (the down side is that you'd have to search for all
existing timers with the same time value to figure out what counter value you
ought to use. ick.).

We should clarify what guarantees are made by callLater. I think there may be
several separate ones here:

 1: callLater(0, A); callLater(0, B)
     will result in A being invoked before B
     will result in both A and B being invoked before any other DelayedCalls

 2: callLater(N, A); callLater(N, B)
     will result in A being invoked before B

 3: callLater(N, A); callLater(N+M, C); callLater(N, B)
     will result in A being invoked before B
     (think of this as a unit test for the adding-epsilon concern above)

The second and third ones are not so important to me, just in terms of what I
need to use it as a plan-coordination tool. I only intend to use this with

To that end, using a separate queue for timers that are ready to go "now"
(i.e. ones that will be fired before calling select() or the like) might be
useful, basically making N=0 a special case. This would avoid the overhead of
inserting the DelayedCall into an arbitrary place and maintaining the
ordering guarantees of #2 and #3, and would avoid an extra select() spin
between the time an N=0 timer was inserted and the time it was fired.

The existing threadCallQueue happens to behave exactly this way, although I'd
want to write some additional tests to make sure it gets serviced as many
times as it's supposed to be (specifically, when threads are unavailable and
therefore wakeUp() is not used, does a call inserted from within an N=0
callback get serviced before the reactor sleeps again?). The problem is both
the word "thread" in the name, and the fact that we might not be making the
same guarantees about the behavior of callFromThread as we are about that of

Hmm. Most reactors split off a list of timers that are ready to go "now" on
each spin, right? And/or there's that _pendingTimedCalls list I see in
t.i.base .. maybe we could take advantage of one of those, just appending the
call to those lists and making sure they'll be serviced again, rather than
adding the overhead of maintaining ordering guarantees #2 and #3.


More information about the Twisted-Python mailing list