threads

This is the place for queries that don't fit in any of the other categories.

threads

Postby metulburr » Tue Mar 05, 2013 1:03 pm

How exactly do you close a thread in 3.x?

Code: Select all
import time
import threading

def print_time(name, delay):
   while True:
      time.sleep(delay)
      print(name)

threading.Thread(target=print_time,
   args=('first thread', 1),).start()

threading.Thread(target=print_time,
   args=('second thread', 3),).start()


time.sleep(4)
print('Not in thread. Main script at end')
New Users, Read This
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1300
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY

Re: threads

Postby Yoriz » Tue Mar 05, 2013 1:19 pm

Maybe you need daemon threads.
A thread can be flagged as a “daemon thread”. The significance of this flag is that the entire Python program exits when only daemon threads are left. The initial value is inherited from the creating thread. The flag can be set through the daemon property or the daemon constructor argument.


have you seen concurrent futures for a much easier way of playing with threads.
There is a back port for 2.7 as well https://pypi.python.org/pypi/futures/2.1.3
New Users, Read This
Join the #python-forum IRC channel on irc.freenode.net!
Spam topic disapproval technician
Windows7, Python 2.7.4., WxPython 2.9.5.0., some Python 3.3
User avatar
Yoriz
 
Posts: 723
Joined: Fri Feb 08, 2013 1:35 am
Location: UK

Re: threads

Postby setrofim » Tue Mar 05, 2013 1:44 pm

Threads do not have a built-in mechanism for stopping. As Yoriz pointed out, marking a Thread as a daemon will allow Python to exist even if the thread is still running (which would terminate the thread, obviously). The problem with this approach is that the thread may have left your system in an inconsistent state (e.g. it may have been in the middle of writing to a file). If you want to terminate threads explicitly, you will need to implement the stop logic yourself. E.g.
Code: Select all
import time
import threading

class MyThread(threading.Thread):

    def __init__(self):
        self._should_stop = threading.Event()
        threading.Thread.__init__(self)

    def run(self):
        while not self._should_stop.is_set():
            # Do stuff
            time.sleep(1)
        self._should_stop.clear()

    def stop(self):
        self._should_stop.set()
        while self._should_stop.is_set():
            time.sleep(1)


t = MyThread()
t.start()
time.sleep(3) # Do something until it's time to terminate
assert threading.active_count() == 2
t.stop()
assert threading.active_count() == 1
setrofim
 
Posts: 288
Joined: Mon Mar 04, 2013 7:52 pm

Re: threads

Postby Yoriz » Tue Mar 05, 2013 11:51 pm

Here an example using concurrent futures, its written in 2.7 but i think its pretty much the same code as 3
It shows how easy it is to get a result back from a thread and how to wait till all threads are finished when you ask them to stop looping.
Code: Select all
from concurrent.futures import ThreadPoolExecutor, wait
import time


class PrintTime(object):
    def __init__(self, name, delay):
        self.name = name
        self.delay = delay
        self.keep_going = True

    def start(self):
        time.clock()
        while self.keep_going:
            time.sleep(self.delay)
            print(self.name)

        return 'PrintTime {} has finished and ran for {}'.format(self.name,
                                                                 time.clock())


executor = ThreadPoolExecutor(2)
first = PrintTime('first thread', 1)
second = PrintTime('second thread', 3)
futures = map(executor.submit, (first.start, second.start))
time.sleep(4)
first.keep_going = False
second.keep_going = False
wait(futures)
for future in futures:
    print(future.result())

print('Not in thread. Main script at end')

Returns the following
Code: Select all
first thread
first thread
first threadsecond thread

first thread
second thread
PrintTime first thread has finished and ran for 4.00254124139
PrintTime second thread has finished and ran for 6.0022758595
Not in thread. Main script at end
New Users, Read This
Join the #python-forum IRC channel on irc.freenode.net!
Spam topic disapproval technician
Windows7, Python 2.7.4., WxPython 2.9.5.0., some Python 3.3
User avatar
Yoriz
 
Posts: 723
Joined: Fri Feb 08, 2013 1:35 am
Location: UK

Re: threads

Postby metulburr » Mon Mar 11, 2013 1:47 pm

Threads do not have a built-in mechanism for stopping. As Yoriz pointed out, marking a Thread as a daemon will allow Python to exist even if the thread is still running (which would terminate the thread, obviously). The problem with this approach is that the thread may have left your system in an inconsistent state (e.g. it may have been in the middle of writing to a file). If you want to terminate threads explicitly, you will need to implement the stop logic yourself. E.g.
Code: Select all
import time
import threading

class MyThread(threading.Thread):

    def __init__(self):
        self._should_stop = threading.Event()
        threading.Thread.__init__(self)

    def run(self):
        while not self._should_stop.is_set():
            # Do stuff
            time.sleep(1)
        self._should_stop.clear()

    def stop(self):
        self._should_stop.set()
        while self._should_stop.is_set():
            time.sleep(1)


t = MyThread()
t.start()
time.sleep(3) # Do something until it's time to terminate
assert threading.active_count() == 2
t.stop()
assert threading.active_count() == 1


Not that a single while loop is much of a resource, but it seems like wasted resources for switching between while loops for each thread. However i could see this useful if you need to swtich between these like switches. I was thinking more of a one time thread run and then its killed.

So i guess my understanding of it is:
You reuse the thread instead of creating a new one for each operation you want or relevant operation, whatever.
New Users, Read This
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1300
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY

Re: threads

Postby setrofim » Mon Mar 11, 2013 2:37 pm

metulburr wrote:Not that a single while loop is much of a resource, but it seems like wasted resources for switching between while loops for each thread. However i could see this useful if you need to swtich between these like switches. I was thinking more of a one time thread run and then its killed.

So i guess my understanding of it is:
You reuse the thread instead of creating a new one for each operation you want or relevant operation, whatever.

My example illustrates a case where the thread is running a continuous task that never terminates (such as continuously monitoring a directory), or a long-running task that can be broken down into discrete steps (which case you would perform a single step inside the while loop and break out of the loop when the step is done). In these cases, the nature of the task is already iterative, so the while loop doesn't really add anything extra. Note that you never actually "switch" between the while loops -- each loop runs in its own thread.

The while loop is necessary for the graceful termination of the thread. Only the thread itself knows what stage of execution it is in, what resources it is currently holding, and what is necessary to clean up before termination. Therefore the only way to achieve graceful termination is to signal the thread to shut down and wait for it to do its own cleanup. If you don't care about graceful termination, then just use daemon threads -- the daemons with simply be killed when the main exits.

My example only deals with a single perpetual/long-running task per thread (since this is when you would typically want to kill a thread, rather than wait for it to finish). The example can be adapted to reuse the same thread for performing several operations by adding a Queue and modifying the run() logic; but if that is what you want, then you should be using a pool, as illustrated by Yoriz. The pool will take care of spawning the desired number of threads and assigning tasks to them as they become available. Note that even in this case you would still need to loop inside your run() if you want graceful termination (again, see Yoriz's example).

EDIT:
You can also use the killable thread recipe that basically extends threading.Thread with a method that raises SystemExit exception on the running thread from main. You then enclose your run target with a try/finally and do your cleanup in the finally clause. This results in somewhat neater client code will perform slightly better (as your not checking termination flag on each iteration), but is a bit hacky, imho (it hooks into unexposed functionality -- see the issues on that page). Also this doesn't integrate well with concurrent.futures, so you'll have to write your pooling code as well (if you need it). If you need high-performing killable threads, however, this is the way to go.
setrofim
 
Posts: 288
Joined: Mon Mar 04, 2013 7:52 pm


Return to General Coding Help

Who is online

Users browsing this forum: No registered users and 4 guests