When would I use dummy_threading
?
I had thought it might replace system-level threads with mock threads in case system-level threads weren't available for Python.
But when I run this:
import dummy_threading as threading
semaphore = threading.Semaphore()
def f(i):
semaphore.acquire()
print i
for i in xrange(10):
threading.Thread(target=f, args=(i,)).start()
for _ in xrange(10):
semaphore.release()
I get 0
, and the program doesn't terminate. Not only that, but Python inexplicably continues to chew up my computer's memory until it has nothing left.
When I run this:
import threading
semaphore = threading.Semaphore()
def f(i):
semaphore.acquire()
print i
for i in xrange(10):
threading.Thread(target=f, args=(i,)).start()
for _ in xrange(10):
semaphore.release()
I get 0 1 3 5 7 9 2 4 6 8
as expected.
I must misunderstand dummy_threading
. When would I use it?
FYI, I tried this on Windows 7 and Fedora 18 for comparison and got the same results.
EDIT: The following, however, gives 0 1 2 3 4 5 6 7 8 9
:
import dummy_threading as threading
event = threading.Event()
def f(i):
event.wait()
print i
for i in xrange(10):
threading.Thread(target=f, args=(i,)).start()
event.set()
The big question is: what does dummy_threading
do, or alternatively when would it give the same behavior as threading
?
The module is meant to be used when thread
and threading
are not available on your platform.
The functions you pass to it are called synchronously, and you called .start()
immediately. The first function acquires the semphore, prints, then the second function is called and blocks. It is run synchronously and never returns.
From the dummy_thread
documentation:
Be careful to not use this module where deadlock might occur from a thread being created that blocks waiting for another thread to be created. This often occurs with blocking I/O.
and from an EFF-bot post (otherwise short and missing a working link):
Helpers to make it easier to write code that use threads where supported, but still runs on Python versions without thread support. The dummy modules simply run the threads sequentially.
Note the making it easier part; without actual threads, you cannot expect code run under dummy_threading
to not deadlock in the manner that it does in your example.
In dummy_threading
, thread are just function wrappers, they are executed sequentially.
The problem with the second snippet is that dummy_threading.Thread.start()
does not return until the corresponding f
call exits. Thread 0
will acquire the semaphore, then thread 1
will attempt to acquire it and block. And nothing will ever release the semaphore because there's only one thread which is blocked.
UPDATE: Made some research about dummy events behaviour.
In fact, all of Semaphore
, Event
, Condition
etc in dummy_threading
are exactly the same as for normal threading
with the exception that they're using dummy locks (there's some importing magic done for this.) As a result, when you call event.wait()
, the underlying lock never blocks the thread. Neither blocks the lock used by Semaphore
, but internally semaphore loops until the resource is available:
while self.__value == 0: # Here it will loop forever
if not blocking:
break
....
self.__cond.wait()
I think, that dummy events violate the assumption that whenever wait
called without arguments returns, it means that the event was set, but not sure if that can be helped easily.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With