threading.Thread.join(timeout=...) considered unreliable

Will Stuyvesant hwlgw at hotmail.com
Mon Oct 14 14:22:30 EDT 2002


In another posting I was asking for a realtime building block
function.  This is what I came up with using threads.  That was
before I realized threads are **not** the way to go.  But the
solution *is* useable if you do not have such a cpu intensive
target function to call.  It is all about the function ``rcall'',
see its doc string there.


---------------  cut here  ------------------------------------
import threading
import time


class ThreadedFunctionCall(threading.Thread):
    def __init__(self, func, *args, **kw):
        self.func = func
        self.args = args
        self.kw = kw
        self.returnvalue = '_not_finished_'
        threading.Thread.__init__(self)
    def run(self):
        self.returnvalue = self.func(*self.args, **self.kw)


def current_time():
    return time.time() * 1000   # ms since Januari 1 1970

def rcall(ms, func, *args, **kw):
    ''' Return func(*args, **kw), unless over ms milliseconds
    time passes.  In that case return 'timeout' in about ms
    milliseconds plus the time it takes for returning.'''
    starttime = current_time()
    t = ThreadedFunctionCall(func, *args, **kw)
    t.start()
    t.join(timeout = ms / 1000.0)
    now = current_time()
    deltatime = now - starttime
    if deltatime > ms:
        return 'timeout'
    else:
        return t.returnvalue


if __name__ == '__main__':

    def testFunctionA(a, b, c, d=2):
        time.sleep(3)   # 3 seconds
        return a+b*c+d

    def testFunctionB(a):
        # takes about 4 seconds with a == 19 on my computer,
        # keeps the cpu *very* busy
        return (2L ** 2L ** a) == 0

    def testF(func, *args, **kw):
        starttime = current_time()
        print rcall(500, func, *args, **kw)
        now = current_time()
        deltatime = now - starttime
        print 'rcall took', deltatime, 'ms'

    # desired behaviour with testFunctionA
    testF(testFunctionA, 1, 2, 3, 4)

    # testFunctionB is too cpu intensive,
    # threading.Thread.join turns out to be useless...
    testF(testFunctionB, 19)
---------------  cut here  ------------------------------------


This outputs:

_not_finished_
rcall took 510.0 ms
timeout
rcall took 3485.0 ms


The desired behaviour would be that the second rcall takes only
slightly over 500 ms too.  But for applications with low cpu usage
this solution is good enough maybe.



'''
QOTD, about ``good enough''

This is probably true in today's market, if you just grafted in some free
software. However, we are also talking about how a market would work where
software does not need to be rewritten and reinvented literally thousands of
times because people don't have any choice. Perhaps the software that would be
written would finally be more useful than add-on cruft for MS-DOS or lousy
"applets" for Netscape or the umpteenth bad implementation of some marginally
useful class for C++. e.g., I don't think "good enough" would be workable in a
world of predominantly free software. The unfree code (it won't go away any
time soon) would also be held up to much higher standards than is done today.
    -- Erik Naggum, in _gnu.misc.discuss_
'''



More information about the Python-list mailing list