There have been a number of postings asking about how to install
timeouts on sockets and such. I have implemented what I think is the
basis of a solution which avoids the necessity of using select() - i.e.
it operates on 'legacy' code.
I had originally played with the idea of a wrapper function which would
timeout a function passed to it. Unfortunately, because there is no way
of killing a thread, only ways to ask it nicely to finish up what its
doing, this simple wrapper wasnt possible.
After a little reading and experimenting, I discovered the following:
Blocked reads and writes on files can be unblocked by closing the file.
Blocked reads and writes on sockets can be unblocked by calling shutdown
(2) on the socket.
In my case, I wanted to implement timeouts on smtplib and DNS
operations. The simplest way was to add a method to those objects/libs
called shutdown() which simply closed/shutdown all the socket and file
handles used by the object. Brutal, but effective.
So with those tools I could now unblock and terminate operations in
progress within those objects. All I needed now was the actual timeout
My application will probably have a whole lot of operations going on
that require timeouts, so the method of having a separate timeout
thread for each operation will probably not be sufficient.
Ive created an EventQueue class.
Instantiate the class, then insert and remove events at your leisure.
An event is a callback scheduled for a some time in the future.
For timeouts youd do something like this:
eq = EventQueue() # instantiates and starts the event queue thread
server = smtplib.SMTP()
evt = eq.insert(20, server.shutdown, (server,))
If you wanted to get really tricky, youd create a function that
searches through an object's dictionary and shutdown(2)'s all socket
objects it finds. I leave this an an excersise for the reader.
heres the code:
from threading import *
_time = time.time
self.queue = 
self.cond = Condition()
self.running = 1
def insert(self, dt, func, args):
evt = (dt + _time(), func, args)
q = self.queue
lo, hi = 0, len(q)
while lo < hi:
mid = (lo+hi)/2
if evt < q[mid]: hi = mid
else: lo = mid+1
if (lo == 0): self.cond.notify()
def remove(self, evt):
i = self.queue.index(evt)
if i == 0: self.cond.notify()
if not self.queue:
elif self.queue > _time():
self.cond.wait(self.queue - _time
(t, func, args) = self.queue
print "closing EventQueue"
self.running = false
if __name__ == '__main__':
n = 1000
eq = EventQueue()
t0 = _time()
evt = [None] * n
for i in range(0,n):
evt[i] = eq.insert(random.random()*10, eventfunc,
for i in range(0,n):
t1 = _time()
print n /( t1-t0-1)
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.