PYTHON

Python Multithreading: Syntax, Usage, and Examples

Python multithreading allows you to run multiple threads in parallel within a single process. This is especially useful for I/O-bound tasks like handling multiple web requests, reading files, or making API calls. Python’s threading module makes it easy to create and manage threads for concurrent execution. However, because of Python’s Global Interpreter Lock (GIL), multithreading doesn’t improve performance for CPU-intensive tasks.


How to Use Python Multithreading

Python provides the threading module for working with threads. To create and start a new thread, you define a function and pass it as the target to a Thread object.

Creating and Running Threads

import threading

def print_numbers():
    for i in range(1, 6):
        print(i)

# Creating a thread
thread = threading.Thread(target=print_numbers)

# Starting the thread
thread.start()

# Waiting for the thread to finish
thread.join()
  • threading.Thread(target=function_name): Creates a thread that runs the specified function.
  • .start(): Begins execution of the thread.
  • .join(): Blocks the main thread until the created thread finishes execution.

When to Use Multithreading in Python

Multithreading is useful when you want to perform multiple tasks at the same time, especially when those tasks involve waiting. Here are three common scenarios where Python multithreading shines:

1. Handling Multiple User Requests in Web Applications

If you’re building a web application, you might need to process multiple user requests simultaneously. Multithreading ensures that one slow request doesn’t block others.

import threading

def handle_request(user_id):
    print(f"Processing request for user {user_id}")

# Creating multiple threads
threads = [threading.Thread(target=handle_request, args=(i,)) for i in range(1, 4)]

for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

2. Downloading Multiple Files Simultaneously

You can download multiple files at once instead of waiting for each to finish before starting the next.

import threading
import time

def download_file(file_name):
    print(f"Downloading {file_name}...")
    time.sleep(2)  # Simulating download time
    print(f"{file_name} downloaded.")

files = ["file1.txt", "file2.txt", "file3.txt"]

threads = [threading.Thread(target=download_file, args=(file,)) for file in files]

for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

3. Keeping a GUI Responsive While Running Background Tasks

In GUI applications, long-running tasks like data processing can make the interface unresponsive. You can use multithreading to keep the UI active while processing data in the background.

import threading
import time
import tkinter as tk

def load_data():
    time.sleep(3)  # Simulating a slow operation
    label.config(text="Data Loaded!")

root = tk.Tk()
root.geometry("200x100")

label = tk.Label(root, text="Loading...")
label.pack()

# Running the task in a separate thread
thread = threading.Thread(target=load_data)
thread.start()

root.mainloop()

Examples of Python Multithreading

Example 1: Running Multiple Tasks Concurrently

import threading

def task(name):
    for _ in range(3):
        print(f"Task {name} is running")

threads = [threading.Thread(target=task, args=(i,)) for i in range(1, 4)]

for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

Example 2: Preventing Race Conditions with Locks

When multiple threads access the same variable, they can interfere with each other. A lock prevents this problem.

import threading

counter = 0
lock = threading.Lock()

def increment():
    global counter
    for _ in range(100000):
        with lock:  # Ensuring only one thread modifies the counter at a time
            counter += 1

threads = [threading.Thread(target=increment) for _ in range(2)]

for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

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

Example 3: Using a Thread Pool for Efficient Task Execution

If you need to run many small tasks, a thread pool can manage threads more efficiently.

import concurrent.futures

def square_number(n):
    return n * n

numbers = [1, 2, 3, 4, 5]

with concurrent.futures.ThreadPoolExecutor() as executor:
    results = executor.map(square_number, numbers)

print(list(results))  # Output: [1, 4, 9, 16, 25]
  • ThreadPoolExecutor automatically manages a pool of worker threads, reducing the overhead of creating and destroying threads.

Learn More About Python Multithreading

Python Multithreading vs. Multiprocessing

Python multithreading is great for I/O-bound tasks, such as network requests, database queries, and file I/O. However, because of the Global Interpreter Lock (GIL), only one thread runs Python code at a time, meaning multithreading won’t speed up CPU-intensive tasks like image processing or machine learning computations.

If you need to maximize CPU usage, use multiprocessing instead.

Using the Python Multithreading Pool

A thread pool efficiently handles multiple threads when you have many short tasks.

import concurrent.futures

def process_data(item):
    return item * 2

data = [10, 20, 30, 40]

with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
    results = executor.map(process_data, data)

print(list(results))  # Output: [20, 40, 60, 80]
  • max_workers=2: Limits the number of threads running at once.

Python Multithreading Libraries

Python provides several libraries for working with multithreading:

  • threading – The built-in module for managing threads.
  • concurrent.futures – Simplifies working with multiple threads using ThreadPoolExecutor.
  • queue – Provides thread-safe data structures like Queue, making it easier to share data between threads.

When to Avoid Multithreading in Python

Multithreading is not helpful for CPU-intensive tasks because of the GIL. For example, if you need to:

  • Perform mathematical calculations on large datasets.
  • Process images, videos, or audio files.
  • Train machine learning models.

In these cases, use the multiprocessing module instead.


Python multithreading is a powerful tool for improving performance in I/O-bound applications. You can use it to handle multiple user requests, download files in parallel, and keep GUI applications responsive. However, if your goal is to speed up CPU-heavy computations, multithreading won’t help—multiprocessing is the better choice.

Learn to Code in Python for Free
Start learning now
button icon
To advance beyond this tutorial and learn Python by doing, try the interactive experience of Mimo. Whether you're starting from scratch or brushing up your coding skills, Mimo helps you take your coding journey above and beyond.

Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.

You can code, too.

© 2025 Mimo GmbH