Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does dummy_threading do?

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?

like image 520
Paul Draper Avatar asked Jan 14 '23 14:01

Paul Draper


2 Answers

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.

like image 69
Martijn Pieters Avatar answered Jan 17 '23 14:01

Martijn Pieters


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.

like image 21
bereal Avatar answered Jan 17 '23 12:01

bereal