Multi-threading in Python - Tutorial
Multi-threading in Python
Multithreading is a concept of executing different pieces of code concurrently. A thread is an entity that can run on the processor individually with its own unique identifier, stack, stack pointer, program counter, state, register set and pointer to the Process Control Block of the process that the thread lives on.
In this tutorial, we will learn with examples how to do multithreading in Python programming.
threading module is used to achieve multithreading in Python.
Create a Thread
To create a thread, you can use threading.Thread()
class. The syntax of the Thread()
class is:
threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
- leave group as None.
- target is the callable object to be invoked by the
run()
method ofThread
. - name is the Thread name that you can provide and refer to later in the program.
- args is the argument tuple for the target invocation.
- kwargs is a dictionary of keyword arguments for the target invocation.
- daemon if set to
True
, will make the thread a daemon thread, meaning it will not block the program from exiting.
Start a Thread
Once you have created a thread using the Thread()
class, you can start it using the start()
method.
t1 = threading.Thread()
t1.start()
Explanation:
- The
Thread
class is instantiated to create a new thread object. - Then,
start()
is called on this object to begin its execution in parallel with the main thread.
Wait Until the Thread is Finished
You can make the main thread wait until a specific thread is finished using the join()
method.
t1.join()
Explanation:
- The
join()
method ensures that the main program waits fort1
to complete before moving on to the next statement. - This is useful when you want to ensure that all threads are completed before the main thread terminates.
Example - Python Multi-threading with Two Threads
In the following example, we will perform multi-threading with two threads. Each thread runs in parallel to the other and is executed whenever processing resources are available to it.
To demonstrate this behavior, we will run a function in each thread that prints ones and twos.
Python Program
import threading
def print_one():
for i in range(10):
print(1)
def print_two():
for i in range(10):
print(2)
if __name__ == "__main__":
# create threads
t1 = threading.Thread(target=print_one)
t2 = threading.Thread(target=print_two)
# start thread 1
t1.start()
# start thread 2
t2.start()
# wait until thread 1 is completely executed
t1.join()
# wait until thread 2 is completely executed
t2.join()
# both threads completely executed
print("Done!")
Explanation:
- The two functions
print_one
andprint_two
are defined to print the numbers 1 and 2, respectively. - Two thread objects
t1
andt2
are created, each targeting one of the functions. - We start both threads using
start()
, allowing them to run concurrently. - Then, we use
join()
to ensure the main thread waits until both threads finish execution before printingDone!
.
Output
1
1
1
2
2
2
1
1
2
1
2
2
2
2
2
2
1
1
1
1
Done!
Example - Multi-threading with Arguments Passed to Threads
In this example, we will pass arguments to the threads. Also, we will demonstrate calling the same target function for different threads with varying arguments.
Python Program
import threading
def print_x(x, n):
for i in range(n):
print(x)
if __name__ == "__main__":
# create threads
t1 = threading.Thread(target=print_x, args=(1, 5))
t2 = threading.Thread(target=print_x, args=(2, 10))
# start thread 1
t1.start()
# start thread 2
t2.start()
# wait until thread 1 is completely executed
t1.join()
# wait until thread 2 is completely executed
t2.join()
# both threads completely executed
print("Done!")
Explanation:
- The function
print_x
is defined to print the valuex
,n
times. - Threads
t1
andt2
are created, each passing different arguments to the function (1 with 5 iterations, and 2 with 10 iterations). - Each thread is started using
start()
and the main thread waits for them to finish usingjoin()
. - The output shows interleaved printing of ones and twos, depending on thread scheduling by the operating system.
Output
1
1
1
2
2
2
2
1
2
1
2
2
2
2
2
Done!
Example - Daemon Threads
Daemon threads are threads that run in the background and are killed automatically when the main program exits, even if they haven't finished executing. These threads are useful for tasks like logging or background monitoring where you don't need to wait for them to finish before the program terminates.
Python Program
import threading
def background_task():
for i in range(5):
print(f'Background task {i}')
if __name__ == "__main__":
# create daemon thread
t1 = threading.Thread(target=background_task, daemon=True)
# start thread
t1.start()
# main program finishes here
print('Main program finished!')
Explanation:
- The
background_task
function runs a simple loop printing background task messages. - A daemon thread is created by setting
daemon=True
when creating the thread. - The thread starts running, but the main program terminates immediately after printing
Main program finished!
. - Since
t1
is a daemon thread, it will be automatically stopped when the main program exits.
Output
Background task 0
Background task 1
Background task 2
Background task 3
Background task 4
Main program finished!
Summary
In this tutorial, we learned how to implement multi-threading in Python programming with detailed examples. We demonstrated how to create threads, start them, wait for them to finish, pass arguments, and work with daemon threads for background tasks.