Python Threading And Multiprocessing

Article by:
Date Published:
Last Modified:

Overview

Python supports threading. However, because of the GIL lock, only one thread is allowed to run at once. There Python threading supports concurrency, but not parallelism. This makes Python threading suitable for IO bound operations, but not for processor bound operations. Most threading functions are made available by adding the code import threading to the top of your Python script.

Gracefully Exiting Multiple Threads

I followed this example at regexprn.com for the most part, except I discovered the example code was buggy and had to make some tweaks, as outlined below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import time
import threading

DEBUG = 0

class MyThread1(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        # A flag to notify the thread that it should finish up and exit
        self.kill_received = False

    def run(self):
        while not self.kill_received:
            self.do_something()

    def do_something(self):

        # Do your thread logic here!

        # Make sure to add some kind of pause as to not starve other threads
        time.sleep(5.0)
    # END | def do_something(self):
# END | class MyThread1(threading.Thread):

# @brief    main() function for script.
# @details  Starts up the individual threads and controls their execution.
def main(args):

    threads = []

    #----- START THE THREADS -----#

    # Start the internet check thread
    print 'Starting MyThread1...'
    t = MyThread1()
    threads.append(t)        
    t.start()
    print 'MyThread1 started...'

    # Start the knob control thread
    print 'Starting MyThread2...'
    t = MyThread2()
    threads.append(t)        
    t.start()
    print 'MyThread2 started...'

    #----- MONITOR THE THREADS -----#

    while len(threads) > 0:
        if DEBUG:
            print 'len(threads) = ', len(threads)
        
        try:
            if DEBUG:
                print 'In try block.'
            # Join all threads using a timeout so it doesn't block
            # Filter out threads which have been joined or are None
            for i in range(len(threads)):
                # Make sure thread still exists
                if threads[i] is not None:
                    if DEBUG:
                        print 'Attemping to join()...'
                    threads[i].join(1)
                    if threads[i].isAlive() is False:
                        if DEBUG:
                            print 'isAlive() is False, removing thread from list...'
                        threads.pop(i)
            if DEBUG:
                print 'Exiting try block...'
        except KeyboardInterrupt:
            print "Ctrl-c received! Sending kill to threads..."
            for t in threads:
                t.kill_received = True
        except Exception as e:
            print "Unknown exception caught! Sending kill to threads...", e
            for t in threads:
                t.kill_received = True

    print 'main() is returning...'

if __name__ == '__main__':
    main(sys.argv)
NOTE

The code in class MyThread1 can be copied to create as many threads as you want (for example, to create MyThread2).

Examples

The Columbus Radio project uses multiple Python threads for the UI control. The code is in the ColumbusRadio repo on GitHub. The threads should gracefully exit if Ctrl-C is pressed in the terminal while they are running.


Authors

Geoffrey Hunter

Dude making stuff.

Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License .

Tags

    comments powered by Disqus