Advanced Concepts in Python Threading: Timer, Semaphore, and Multiprocessing

Investigate advanced features such as threading.Timer, Semaphore, and the differences between threading and multiprocessing in order to get the most of Python threading.


1. threading.Timer

By utilizing the threading.Timer class, you may provide a time delay for a function’s execution.

It helps with task scheduling without causing the main thread to stall.

Example:

import threading

def delayed_message():
    print("This message is delayed by 5 seconds!")

# Create a timer
timer = threading.Timer(5.0, delayed_message)
timer.start()

2. Semaphore

A ~Semaphore` is a synchronization primitive that regulates how many threads can access a shared resource. It is especially helpful when you wish to restrict how many threads can access a resource at once.

Example:

import threading
import time

semaphore = threading.Semaphore(2)  # Allow only 2 threads to access the resource at a time

def access_shared_resource(thread_id):
    with semaphore:
        print(f"Thread {thread_id} is accessing the resource.")
        time.sleep(2)
        print(f"Thread {thread_id} is done.")

threads = [threading.Thread(target=access_shared_resource, args=(i,)) for i in range(5)]

for t in threads:
    t.start()

for t in threads:
    t.join()

3. Threading vs. Multiprocessing

Threading and multiprocessing serve different purposes even if they are both used for concurrent execution:

FeatureThreadingMultiprocessing
Execution ModelMultiple threads within a single processMultiple independent processes
Best ForI/O-bound tasksCPU-bound tasks
Memory SharingShared memory spaceSeparate memory space
Global Interpreter Lock (GIL)Affected (limits CPU-bound performance)Not affected
OverheadLower (no process creation overhead)Higher (process creation and inter-process communication)

Example of Multiprocessing:

from multiprocessing import Process

def print_numbers():
    for i in range(5):
        print(f"Number: {i}")

# Create and start a process
process = Process(target=print_numbers)
process.start()
process.join()

print("Process execution completed!")

When to Use Each:

  • Threading: When the task involves I/O operations like file handling, network requests, or database access.
  • Multiprocessing: When the task is CPU-intensive, such as computations or simulations.

Would you like detailed examples for a specific use case or comparison?

Leave a Comment