]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Thread.start() used sleep(0.000001) to make sure it didn't return before the
authorJeffrey Yasskin <jyasskin@gmail.com>
Thu, 28 Feb 2008 06:09:19 +0000 (06:09 +0000)
committerJeffrey Yasskin <jyasskin@gmail.com>
Thu, 28 Feb 2008 06:09:19 +0000 (06:09 +0000)
new thread had started. At least on my MacBook Pro, that wound up sleeping for
a full 10ms (probably 1 jiffy). By using an Event instead, we can be absolutely
certain that the thread has started, and return more quickly (217us).

Before:
$  ./python.exe -m timeit -s 'from threading import Thread'  't = Thread(); t.start(); t.join()'
100 loops, best of 3: 10.3 msec per loop
$  ./python.exe -m timeit -s 'from threading import Thread; t = Thread()'  't.isAlive()'
1000000 loops, best of 3: 0.47 usec per loop

After:
$  ./python.exe -m timeit -s 'from threading import Thread'  't = Thread(); t.start(); t.join()'
1000 loops, best of 3: 217 usec per loop
$  ./python.exe -m timeit -s 'from threading import Thread; t = Thread()'  't.isAlive()'
1000000 loops, best of 3: 0.86 usec per loop

To be fair, the 10ms isn't CPU time, and other threads including the spawned
one get to run during it. There are also some slightly more complicated ways to
get back the .4us in isAlive() if we want.

Lib/threading.py

index 005d40c63ed1fc63ea8eca5e019a4a5692483ef0..86153b0f5c1f4437bf778116d7207ce02fa99807 100644 (file)
@@ -404,7 +404,7 @@ class Thread(_Verbose):
         self.__args = args
         self.__kwargs = kwargs
         self.__daemonic = self._set_daemon()
-        self.__started = False
+        self.__started = Event()
         self.__stopped = False
         self.__block = Condition(Lock())
         self.__initialized = True
@@ -419,7 +419,7 @@ class Thread(_Verbose):
     def __repr__(self):
         assert self.__initialized, "Thread.__init__() was not called"
         status = "initial"
-        if self.__started:
+        if self.__started.isSet():
             status = "started"
         if self.__stopped:
             status = "stopped"
@@ -430,7 +430,7 @@ class Thread(_Verbose):
     def start(self):
         if not self.__initialized:
             raise RuntimeError("thread.__init__() not called")
-        if self.__started:
+        if self.__started.isSet():
             raise RuntimeError("thread already started")
         if __debug__:
             self._note("%s.start(): starting thread", self)
@@ -438,8 +438,7 @@ class Thread(_Verbose):
         _limbo[self] = self
         _active_limbo_lock.release()
         _start_new_thread(self.__bootstrap, ())
-        self.__started = True
-        _sleep(0.000001)    # 1 usec, to let the thread run (Solaris hack)
+        self.__started.wait()
 
     def run(self):
         try:
@@ -472,7 +471,7 @@ class Thread(_Verbose):
 
     def __bootstrap_inner(self):
         try:
-            self.__started = True
+            self.__started.set()
             _active_limbo_lock.acquire()
             _active[_get_ident()] = self
             del _limbo[self]
@@ -581,7 +580,7 @@ class Thread(_Verbose):
     def join(self, timeout=None):
         if not self.__initialized:
             raise RuntimeError("Thread.__init__() not called")
-        if not self.__started:
+        if not self.__started.isSet():
             raise RuntimeError("cannot join thread before it is started")
         if self is currentThread():
             raise RuntimeError("cannot join current thread")
@@ -621,7 +620,7 @@ class Thread(_Verbose):
 
     def isAlive(self):
         assert self.__initialized, "Thread.__init__() not called"
-        return self.__started and not self.__stopped
+        return self.__started.isSet() and not self.__stopped
 
     def isDaemon(self):
         assert self.__initialized, "Thread.__init__() not called"
@@ -630,7 +629,7 @@ class Thread(_Verbose):
     def setDaemon(self, daemonic):
         if not self.__initialized:
             raise RuntimeError("Thread.__init__() not called")
-        if self.__started:
+        if self.__started.isSet():
             raise RuntimeError("cannot set daemon status of active thread");
         self.__daemonic = daemonic
 
@@ -672,7 +671,7 @@ class _MainThread(Thread):
 
     def __init__(self):
         Thread.__init__(self, name="MainThread")
-        self._Thread__started = True
+        self._Thread__started.set()
         _active_limbo_lock.acquire()
         _active[_get_ident()] = self
         _active_limbo_lock.release()
@@ -718,7 +717,7 @@ class _DummyThread(Thread):
         # instance is immortal, that's bad, so release this resource.
         del self._Thread__block
 
-        self._Thread__started = True
+        self._Thread__started.set()
         _active_limbo_lock.acquire()
         _active[_get_ident()] = self
         _active_limbo_lock.release()