In this post, we will see how to use multithreading in Python, following the posts that I created for C#.
How we know, multithreading is a programming technique that allows multiple threads of execution to run concurrently within a single process. Each thread can perform a different task or execute a different portion of code, and they can communicate and share data with each other using synchronization mechanisms like locks or semaphores.
It is important to highlight that, due to the Global Interpreter Lock (GIL) in CPython, multithreading may not be as effective for CPU-bound tasks that require a lot of computational power.
The Global Interpreter Lock (GIL) is a mechanism in the CPython interpreter that ensures that only one thread can execute Python bytecode at a time. This means that even in a multi-threaded Python program, only one thread can execute Python code at any given time, while other threads wait for the GIL to be released.
Alternatively, we can use multiprocessing instead of multithreading to achieve parallelism in our Python code. Unlike multithreading, which shares a single process and memory space, multiprocessing creates separate processes with their own memory space, allowing them to run in parallel on multiple CPU cores.
We will see the Multiprocessing technique in the next posts.
Let’s take a look at some examples.
We open Visual Studio Code and we create a file called multy.py, where we will write this code:
[MULTY.PY]
# We import this module to use Thread
import threading
# We import this module to manipulate time values.
import time
# We define three methods used to simulate a real 'workflow'.
def printMethod1():
for i in range(1, 3):
print(f"printMethod1 => {i} ThreadId => {threading.get_ident()}")
# The system will wait 1 second every loop cycle
time.sleep(1)
def printMethod2():
for i in range(1, 4):
print(f"printMethod2 => {i} ThreadId => {threading.get_ident()}")
# The system will wait 1 second every loop cycle
time.sleep(1)
def printMethod3():
for i in range(1, 5):
print(f"printMethod3 => {i} ThreadId => {threading.get_ident()}")
# The system will wait 1 second every loop cycle
time.sleep(1)
# We create three Threads to call the three methods above
thread1 = threading.Thread(target=printMethod1)
thread2 = threading.Thread(target=printMethod2)
thread3 = threading.Thread(target=printMethod3)
# We run the Threads
thread1.start()
thread2.start()
thread3.start()
If we run the file, the following will be the result:
Finally, we see how to call a method in a Thread passing a value in input:
[MULTY.PY]
# We import this module to use Thread
import threading
# We import this module to manipulate time values.
import time
# We define a method used to simulate a real 'workflow'.
def printMethod(inputValue):
for i in range(1, inputValue):
print(f"printMethod{inputValue} => {i} ThreadId => {threading.get_ident()}")
# The system will wait 1 second every loop cycle
time.sleep(1)
# We create three Thread that will call the method printMethod, passing in
# input a different value
thread1 = threading.Thread(target=printMethod, args=(4,))
thread2 = threading.Thread(target=printMethod, args=(5,))
thread3 = threading.Thread(target=printMethod, args=(6,))
# We run the Threads
thread1.start()
thread2.start()
thread3.start()
If we run the file, the following will be the result: