Introduction: How to Communicate and Share Data Between Running Python Threads Using Threading Module

In this Instructable, we'll explore the fundamentals of concurrent programming in Python using the threading module. Learn how to facilitate seamless communication and efficient data sharing between running Python threads to enhance the performance of your applications.

The Original Article along with the Source codes used in this Instructable can be found below.


Supplies

  • Python installed on your computer (version 3.x recommended)
  • Basic understanding of Python programming concepts
  • Text Editor

Step 1: Creating a Thread in Python

Creating a thread in Python involves utilizing the threading module, which provides a high-level interface for working with threads. Here's a basic example demonstrating how to create a thread in Python:

import threading

# Define a function to be executed by the thread
def my_function():
  print("Thread is executing...")

# Create a thread
my_thread = threading.Thread(target=my_function)

# Start the thread
my_thread.start()

# Wait for the thread to finish (optional)
my_thread.join()

print("Main thread continues...")


In this example:

  • We define a function my_function() that represents the task to be performed by the thread.
  • We create a threading.Thread object named my_thread, specifying the target parameter as the function my_function.
  • We start the thread by calling the start() method on the my_thread object.
  • Optionally, we can call the join() method to wait for the thread to finish its execution before continuing with the main thread.
  • Finally, we print a message to indicate that the main thread continues its execution.

This is a basic example, and threading in Python offers more advanced features for synchronization, communication, and coordination between threads, allowing you to build powerful concurrent applications

Step 2: Extracting Values From Python Threads


Once tasks are completed within a thread, such as calculations or downloading data, there's often a need to transfer this data between threads, particularly to the main thread. However, the threading.Thread() class lacks built-in methods for returning data from threads, necessitating alternative approaches to access valuable thread-generated data.

The two main ways of doing it are 


  1. Extend the threading.Thread() class and store the data in instance variable 
  2. Use Global Variables to return data from thread

Step 3: Using Global Values to Return Data From a Python Threads

Utilizing a global variable to return data from threads offers a straightforward solution, particularly for simpler applications. In the following example, we'll illustrate this approach by performing addition within a thread and transmitting the sum back to the main thread via a global variable.

Partial Code only

def add_two_numbers(no1,no2):
global global_sum
global_sum = no1 + no2

global_sum = 0 # Global Value used to return data from thread
print(f'Sum Intial Value -> {global_sum}')
t1 = threading.Thread(target = add_two_numbers,args=(5,10))

Full code on Using Global Values To Return Data From A Python Threads


  1. Here we are declaring a global variable named "global_sum "to store the Sum.
  2. The function add_two_numbers(no1,no2) calculates the sum(5+10=15) inside the thread and stores Sum in the global variable "global_sum "
  3. The main thread then prints out the global variable global_sum (15)


Step 4: Using a Mutable List to Transfer Data Between Python Threads

In Python, a list is a versatile data structure used to store a collection of elements in a specific order. Lists are mutable, meaning that their elements can be modified after the list is created. This flexibility allows for dynamic manipulation of the list's contents, such as adding or removing elements, changing values, or reordering items. Mutable objects in Python can be altered or modified in-place, distinguishing them from immutable objects like tuples or strings, which cannot be changed once created.

Alternatively, you can utilize a List or Dictionary to exchange information between two threads. In this example, we append a list with a string within the thread, directly accessing the global variable from within the thread


def append_list_thread():
global_list.append('Appended in append_list_thread()')

global_list = [] #Create empty global list
global_list.append('Appended in Main Thread')
print(global_list) #before calling the thread
t1 = threading.Thread(target = append_list_thread)


Full code

Output of the above code

['Appended in Main Thread']
['Appended in Main Thread', 'Appended in append_list_thread()']

In the above code we are accessing the shared variable directly, You can also pass the global_list  as an argument through the threading.Thread(target,args) as shown below


global_list = []  # Create empty global list
t1 = threading.Thread(target = append_list_thread,args = (global_list,) ) #global_list as an argument,instead of direct accessing it