Threading in python

Introduction

Threading refers to the ability of a program to manage multiple threads of execution within a single process. A thread is a sequence of instructions within a program that can be executed independently of other threads. Threading allows multiple operations to run in parallel, making your program more efficient, especially on multi-core processors.

Why Use Threading?

  • Concurrency: Threads run concurrently, enabling a program to perform multiple operations simultaneously.
  • I/O-bound Operations: Ideal for tasks that involve waiting for external resources.
  • Improved Performance: Helps in better CPU utilization for I/O-bound and network-bound applications.

Key Concepts

  • Thread: A single sequence of execution within a process.
  • Multithreading: The process of executing multiple threads concurrently.
  • GIL: A mutex in Python that protects access to python objects, limiting the execution of threads to one at a time for CPU-bound operations.

When to Use Threading

  • I/O-bound Tasks: For tasks like file reading/writing, web scraping, network communication
  • Real-time Applications: In applications that require real-time updates like GUI applications or games.
  • Background Tasks: For executing periodic or continuous background tasks like monitoring, logging, scheduled jobs.

Module

Creating a Thread: You can create a thread by instantiating the Thread class from the threading module.

import threading

def fun():
    for i in range(5):
        print(i)

# creating a thread
thread = threading.Thread(target=fun)
# start the thread
thread.start()
# waiting for the thread to finish
thread.join()

Using Thread Subclassing: Another way to create threads is by subclassing the Thread class and overriding the run method.

import threading

class MyThread(threading.Thread):
    def run(self):
        for i in range(5):
            print(f"Thread {self.name}: {i}")

thread = MyThread()
thread.start()
thread.join()

Synchronization with Locks: To avoid race condition when multiple threads access shared resources, use a Lock.

import threading

counter = 0
lock = threading.Lock()

def increment():
    global counter
    # acquire the lock before modifying the counter
    with lock:
        counter += 1

threads = []
for _ in range(10):
    thread = threading.Thread(target=increment)
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join()

print(f"Final counter: {counter}")

Threading with ThreadPoolExecutor: The ThreadPoolExecutor from the concurrent.futures module simplifies thread management by using a pool of threads.

from concurrent.futures import ThreadPoolExecutor

def square(n):
    return n*3

numbers = [1,2,3,4,5]
with ThreadPoolExecutor() as executor:
    results = executor.map(square, numbers)

print(list(results))

Daemon Threads: Daemon threads run in the background and automatically terminate when the main program exits.

import threading
import time

def background_task():
    while True:
        print("Running in background.....")
        time.sleep(1)

thread = threading.Thread(target=background_task)
thread.daemon = True
thread.start()
time.sleep(5)
print("Main thread finished.")

For More Blog Visit

Python – pytechie.com

threading — Thread-based parallelism — Python 3.13.1 documentation

Leave a Reply