Laughing at myself

Bengt Richter bokr at oz.net
Mon May 12 17:30:48 EDT 2003


On Mon, 12 May 2003 10:12:34 -0600, "Daniel Fackrell" <unlearned at DELETETHIS.learn2think.org> wrote:

>Just to make sure that everyone else can get some benefit from my
>self-induced pain:
>
>I have wasted a bit of time recently, wondering why Python doesn't offer a
>usleep() (sleep for microseconds) function.  I had found the time module,
>and used its time.sleep(), but was frustrated that it didn't have a
>time.usleep() as well.  After searching the web and the newsgroup archives,
>I finally figured I might get stuck implementing something like this at a
>low level.
>
>After all that, I was just reading a recent post reminding about the dangers
>of explicit type-checking reducing polymorphism, and somehow that reminded
>me of my problem.  I had been assuming (courtesy of my strongly-typed
>background) that time.sleep() took in integer argument, but in fact it takes
>any numerical argument, so that:
>
>time.sleep(0.000001)
>
>works just fine, and apparently perfectly.
>
But note the limitations mentioned in the docs. YMMV according to platform
as to what happens in real time. Be aware that a "perfect" 1-microsecond sleep
is not too likely ;-)

A quick-n-dirty test follows (NT4, Python 2.2.2)

====< sleept.py >=================================================
from time import clock, sleep
import math
def sleept(n, delta):
    snoozes = [0]*n
    for i in xrange(n):
        t = clock()
        sleep(delta)
        snoozes[i] = clock()-t
    snoozes = map(float(-delta).__add__, snoozes) # errors from delta
    mean = reduce(float.__add__, snoozes)/(n-1.0)
    rms = reduce(float.__add__, map(lambda x:(x-mean)**2, snoozes))/(n-1.0)
    return mean, math.sqrt(rms)

if __name__ == '__main__':
    import sys
    try:
        n, delta = int(sys.argv[1]), float(sys.argv[2]) 
        mean, sd = sleept(n, delta)
        print 'Sleeping %s times for %f seconds => mean error %f, sd %f' % (
            n, delta, mean, sd)
    except Exception, e:
        print e; print
        print 'Usage: sleept nloops sleeptime'
==================================================================
Note what happens, presumably because the NT scheduler works on 10ms slices:

[13:38] C:\pywk\clp>sleept.py 1000 .002
Sleeping 1000 times for 0.002000 seconds => mean error 0.008042, sd 0.001010

[13:38] C:\pywk\clp>sleept.py 1000 .010
Sleeping 1000 times for 0.010000 seconds => mean error 0.000027, sd 0.000688

[13:38] C:\pywk\clp>sleept.py 1000 .012
Sleeping 1000 times for 0.012000 seconds => mean error 0.008111, sd 0.001428

    The 2ms offset seems to cause a wait for the next tick, hence the ~ 8ms error.
    The theory seems to hold with an 8 ms offset from an even tick:

[13:39] C:\pywk\clp>sleept.py 1000 .018
Sleeping 1000 times for 0.018000 seconds => mean error 0.002068, sd 0.001183

    Or

[13:42] C:\pywk\clp>sleept.py 1000 .038
Sleeping 1000 times for 0.038000 seconds => mean error 0.002042, sd 0.000397

    Of course, if other things are going on, YM will V even more, unless you
    are running at real time priority and preempting whatever else. And apparently
    signals can cut sleep short, so it can vary both ways. Most informative
    would be a scatter plot showing requested vs actual sleep time. I think it
    would be a fuzzy stair case with a sprinkling of outliers.

>Thanks to Alex Martelli for being the one who set me a bit closer to the
>true path.

I too am among the many who are indebted here, though I prefer to think we
all find our true paths ourselves. Of course, Alex leaves big footsteps ;-)

Regards,
Bengt Richter




More information about the Python-list mailing list