Python

P
PythonHub
Progress 0%

Python

  • Home
  • History of Python
  • Applications of Python
  • Introduction To Python
    • What is Python
    • Character Set
    • Tokens in Python
    • Python Execution Mode
    • Variable And Identifiers
    • Data Types in Python
    • Operators And Expressions
    • Constants in Python
    • Assignment Statement
    • Input / Output in Python
    • Simple Python Scripts
    • Namespace in Python
    • πŸ“ Assignments
  • Operators in Python
    • Arithmetic Operators
    • Assignment Operators
    • Shorthand Assignment Operators
    • Relational Operators
    • Logical Operators
    • Bitwise Operators
    • Special Operators
    • πŸ“ Assignments
  • Input Output in Python
    • Accept Input
    • Output Formatting
    • πŸ“ Assignments
  • Conditional Statement
    • Decision Making
    • if Statement
    • IF-ELSE STATEMENT
    • IF-ELSE LADDER
    • NESTED IF-ELSE
    • Short Hand IF-ELSE
    • πŸ“ Assignments
  • Loops
    • Introduction to Loops
    • While Loop
    • Nested While Loop
    • πŸ“ While Loop Assignments
    • For Loop
    • For Loop Examples
    • Nested For Loop
    • Nested For Loop Examples
    • Infinite While Loops
    • Infinite For Loops
    • Break, Continue and Else in Loops
    • Difference Between For and While Loop
    • For Each Loop
    • πŸ“ For Each Assignments
    • πŸ“ All Loops Assignments
  • List
    • List in Python
    • Access List Elements
    • List Functions
    • Iterate (Loop) List
    • List Comprehension
    • πŸ“ Assignments
  • Tuple
    • Tuple in Python
    • Access Tuple Elements
    • Tuple Functions
    • Iterate (Loop) Tuple
    • Unpack Tuple
    • Tuple Comprehension
    • πŸ“ Assignments
  • Set
    • Set in Python
    • Access Set Elements
    • Set Methods
    • Iterate (Loop) Set
    • Pack/Unpack Set
    • Set Comprehension
    • πŸ“ Assignments
  • Dictionary
    • Dictionary
    • Access Dictionary Items
    • Dictionary Methods
    • Iterate (Loop) Dictionary
    • Formatting Dictionaries
    • Nested Dictionaries
    • Dictionary Comprehension
    • πŸ“ Assignments
  • Diff List Tuple Set Dictionary
    • List vs Tuple
    • List vs Set
    • List vs Dictionary
    • Tuple vs Set
    • Tuple vs Dictionary
    • Dictionary vs Set
    • πŸ“ Assignments
  • Exception
    • Error vs Exception
    • Types of Exception
    • Exception Handling
    • User Defined Exception
    • Logging Exception
    • πŸ“ Assignments
  • Functions
    • Introduction to Functions
    • Modular Programming
    • Types of Functions
    • Inbuilt Functions
    • Need For User-Defined Function
    • Elements of User Defined Function
    • Function Arguments
    • Nesting of Functions
    • Recursion
    • Global Local and Non Local
    • Python Lambda Functions
    • πŸ“ Assignments
  • Python Module
    • Introduction to Module
    • Inbuilt Modules in Python
    • User Defined Module
    • πŸ“ Assignments
  • File Handling
    • Introduction to Files
    • Create File
    • Read Files
    • Write to File
    • Rename File
    • Copy File
    • Move File
    • List Files in Directory
    • Binary Files
    • Zipping and Unzipping Files
    • πŸ“ Assignments
  • Strings
    • Basics of Strings
    • String Special Operators
    • String Formatting Operators
    • String Methods
    • πŸ“ Assignments
  • Regular Expressions
  • Python OOPS
    • Basics of Object Oriented
    • What are Classes and Objects?
    • Creating Class and Object
    • OOP vs Procedural Programming
    • Difference Between Classes and Objects
    • Constructors
    • Destructor
    • Built Class Methods and Attributes
    • Class and Instance Variables
    • Inheritance in Python
    • Single Inheritance
    • Multiple Inheritance
    • Multilevel Inheritance
    • Hierarchical Inheritance
    • Hybrid Inheritance
    • Abstraction
    • Method Overriding
    • Abstract Method
    • Interfaces in Python
    • Abstract Class vs Interface
    • Public, Private and Protected
    • Overloading vs Overriding
    • Inheritance vs Composition
    • Encapsulation
    • Polymorphism
    • Inner Classes
    • πŸ“ Assignments
  • Advanced Python
    • Iterator in Python
    • Generator in Python
    • Decorator in Python
    • Type Hints in Python
    • Async/Await Programming
    • Dataclasses in Python
    • Context Managers in Python
    • Property Decorator in Python
    • __slots__ in Python
    • Enums in Python
    • Walrus Operator in Python
    • Match-Case in Python
    • πŸ“ Assignments
  • Python Standard Library
    • Collections Module
    • Itertools Module
    • Functools Module
    • Datetime Module
    • JSON Module
    • OS Module
    • Sys Module
    • Random Module
    • Math Module
    • πŸ“ Assignments
  • Python Testing
    • Unit Testing in Python
    • Pytest Framework
    • Mocking in Python
    • πŸ“ Assignments
  • Python Best Practices
    • PEP 8 Style Guide
    • Docstrings in Python
    • Logging in Python
    • Code Optimization Tips
    • Debugging Techniques
    • πŸ“ Assignments
  • MySQL Database in Python
    • Introduction to MySQL with Python
    • DBMS vs File System
    • Connecting to MySQL Database
    • Create Database in MySQL
    • Create Table in MySQL
    • Insert Data in MySQL
    • Insert Multiple Rows
    • Select Data from MySQL
    • WHERE Clause in MySQL
    • Update Data in MySQL
    • Delete Data from MySQL
    • Parameterized Queries
    • Transaction Management
    • Error Handling
    • Connection Pooling
    • MySQL Drivers Guide
    • Joins in MySQL
    • Aggregation Functions
    • Backup MySQL Database
    • Best Practices
    • πŸ“ Assignments
  • MySQL Database Operations
    • SELECT Statement
    • MySQL Operators
    • DDL Statements
    • DML Statements
    • Subqueries
    • JOIN Operations
    • Aggregation
    • Case Study
    • πŸ“ Assignments
  • Graphics in Python
  • Threads in Python
    • Introduction to Threads
    • Process vs Threads
    • Concurrent Programming & GIL
    • Uses of Threads
    • Creating Threads
    • Single Tasking
    • Multi Tasking
    • Thread Synchronization
    • πŸ“ Assignments
  • Interview Questions & Answers
  • Python Case Studies
  • Multiple Choice Questions
  • πŸ“ Practice Problems
Get in Touch
  • tech2dsm@gmail.com

© Sankalan Data Tech

Python Language Interactive Tutorial

Python: Multi Tasking

Python Multi Tasking - Complete Guide

Learn how to do multiple things at once in Python.

Created by Sankalan Data Tech Team Verified
Data Engineers, Analysts, Scientists & Trainers
Created by experienced Python developers, data engineers, and data scientists to make programming easy through practical examples, real-world experience, and clear explanations.
Read Time: 10 minutes Level: Intermediate Topic: Python Concurrency Focus: Concurrent Execution
On this page:
  • What is Multi Tasking?
  • Threading
  • Multiprocessing
  • Asynchronous Programming
  • Method Comparison
  • When to Use Which
  • Real-World Example
  • Best Practices
  • Try It Yourself
  • Quiz
  • FAQ
Share this tutorial:
Twitter LinkedIn Facebook WhatsApp Reddit Telegram Email Copy Link
What You'll Learn Here
  • What is multi-tasking β€” doing multiple things at once
  • Threading β€” lightweight concurrent execution
  • Multiprocessing β€” using multiple CPU cores
  • Asynchronous programming β€” event-driven concurrency
  • When to use each β€” choosing the right approach

What is Multi Tasking?

Multi-tasking means doing multiple things at the same time. In programming, it means executing multiple tasks concurrently, making your program faster and more efficient.

🍳 Think of it like a restaurant kitchen.

Single tasking: One chef does everything β€” takes orders, cooks, cleans. Everything is slow.

Multi-tasking: Multiple chefs work simultaneously β€” one takes orders, another cooks, another cleans. Everything is fast and efficient!

Threading

Lightweight threads for I/O-bound tasks

Multiprocessing

Processes for CPU-bound tasks

Asynchronous

Event-driven for high concurrency

Combined

Mix approaches for best results

πŸ’‘ Key concept: Multi-tasking makes your program faster by utilizing system resources more efficiently.

1

Multi-Tasking in Action

# ============================================================
# MULTI-TASKING EXAMPLE
# ============================================================

import threading
import time

def task1():
    print("Task 1: Starting...")
    time.sleep(2)
    print("Task 1: Finished!")

def task2():
    print("Task 2: Starting...")
    time.sleep(2)
    print("Task 2: Finished!")

def task3():
    print("Task 3: Starting...")
    time.sleep(2)
    print("Task 3: Finished!")

print("=" * 40)
print("MULTI-TASKING IN ACTION")
print("=" * 40)

print("\nRunning tasks in parallel...")

start = time.time()

# Create threads
t1 = threading.Thread(target=task1)
t2 = threading.Thread(target=task2)
t3 = threading.Thread(target=task3)

# Start threads
t1.start()
t2.start()
t3.start()

# Wait for threads
t1.join()
t2.join()
t3.join()

end = time.time()
print(f"\nAll tasks completed in {end - start:.2f} seconds")

print("""
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ OBSERVATIONS:                                                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ Tasks run simultaneously                                   β”‚
β”‚ β€’ Total time = time of slowest task (not sum of all)         β”‚
β”‚ β€’ Much faster than single tasking                            β”‚
β”‚ β€’ More complex than single tasking                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
""")

Key point: Multi-tasking runs tasks in parallel, reducing total execution time.

Quick Check: What is multi-tasking? (Answer: Doing multiple things at the same time)

Threading

2

Lightweight Concurrent Execution

Threading is the most common way to do multi-tasking in Python. Threads are lightweight and share memory, making them efficient for I/O-bound tasks.

# ============================================================
# THREADING EXAMPLE
# ============================================================

import threading
import time
import random

# ============================================================
# BASIC THREADING
# ============================================================

def download_file(file_name):
    """Simulate downloading a file"""
    thread_name = threading.current_thread().name
    size = random.randint(1, 5)
    
    print(f"[{thread_name}] Downloading {file_name} ({size}MB)")
    
    for progress in range(0, 101, 20):
        time.sleep(random.uniform(0.1, 0.3))
        print(f"[{thread_name}] {file_name}: {progress}%")
    
    print(f"[{thread_name}] {file_name}: Complete!")

# Create and start threads
files = ["file1.mp4", "file2.pdf", "file3.jpg", "file4.exe"]
threads = []

for file_name in files:
    t = threading.Thread(target=download_file, args=(file_name,))
    threads.append(t)
    t.start()

# Wait for all threads
for t in threads:
    t.join()

print("All downloads complete!")

# ============================================================
# THREADING WITH POOL
# ============================================================

from concurrent.futures import ThreadPoolExecutor

print("\n" + "=" * 40)
print("THREAD POOL EXECUTOR")
print("=" * 40)

def process_data(data_id):
    """Process data with ThreadPoolExecutor"""
    time.sleep(random.uniform(0.2, 0.5))
    return f"Data {data_id} processed"

# Use ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=4) as executor:
    results = executor.map(process_data, range(10))
    
    for result in results:
        print(result)

print("""
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ THREADING ADVANTAGES:                                         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ Lightweight (low memory overhead)                          β”‚
β”‚ β€’ Share memory (fast communication)                          β”‚
β”‚ β€’ Great for I/O-bound tasks                                 β”‚
β”‚ β€’ Easy to implement                                          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ THREADING DISADVANTAGES:                                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ GIL limits CPU-bound performance                          β”‚
β”‚ β€’ Race conditions (need synchronization)                    β”‚
β”‚ β€’ Not for CPU-intensive work                                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
""")

Threading key points:

  • Lightweight β€” low memory overhead
  • Shared memory β€” fast communication
  • I/O-bound β€” great for waiting tasks
  • GIL limited β€” not for CPU work

Quick Check: What type of tasks are threads best for? (Answer: I/O-bound tasks)

Multiprocessing

3

Using Multiple CPU Cores

Multiprocessing creates separate processes, each with its own memory space. This bypasses the GIL and allows true parallelism for CPU-bound tasks.

# ============================================================
# MULTIPROCESSING EXAMPLE
# ============================================================

from multiprocessing import Pool, Process
import time
import math

# ============================================================
# CPU-BOUND TASK
# ============================================================

def cpu_intensive_task(n):
    """Calculate factorial (CPU-intensive)"""
    result = math.factorial(n)
    return f"Factorial of {n} is {result}"

def run_with_processes():
    """Run tasks with processes"""
    numbers = [100000, 120000, 140000, 160000]
    
    print("\nRunning with processes (parallel):")
    start = time.time()
    
    with Pool(processes=4) as pool:
        results = pool.map(cpu_intensive_task, numbers)
    
    end = time.time()
    print(f"Time: {end - start:.2f}s")
    
    for result in results:
        print(result)

def run_with_threads():
    """Run tasks with threads"""
    numbers = [100000, 120000, 140000, 160000]
    
    print("\nRunning with threads (GIL limited):")
    start = time.time()
    
    from concurrent.futures import ThreadPoolExecutor
    with ThreadPoolExecutor(max_workers=4) as executor:
        results = list(executor.map(cpu_intensive_task, numbers))
    
    end = time.time()
    print(f"Time: {end - start:.2f}s")
    
    for result in results:
        print(result)

# ============================================================
# COMPARE PERFORMANCE
# ============================================================

print("=" * 60)
print("PROCESSES vs THREADS - CPU-BOUND TASK")
print("=" * 60)

print("""
This task is CPU-intensive (calculating factorials).
Threads are limited by the GIL, processes are not.

Expected: Processes will be faster than threads.
""")

run_with_processes()
run_with_threads()

print("""
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ MULTIPROCESSING ADVANTAGES:                                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ True parallelism on multi-core CPUs                        β”‚
β”‚ β€’ Bypasses the GIL                                            β”‚
β”‚ β€’ Great for CPU-bound tasks                                  β”‚
β”‚ β€’ Isolated (one crash doesn't affect others)                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ MULTIPROCESSING DISADVANTAGES:                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ Higher memory usage                                         β”‚
β”‚ β€’ Slower to create processes                                 β”‚
β”‚ β€’ Communication is slower (IPC)                             β”‚
β”‚ β€’ More complex than threading                                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
""")

Multiprocessing key points:

  • True parallelism β€” uses multiple cores
  • Bypasses GIL β€” no limitation
  • CPU-bound β€” great for calculations
  • Isolated β€” processes don't share memory

Quick Check: What type of tasks are processes best for? (Answer: CPU-bound tasks)

Asynchronous Programming

4

Event-Driven Concurrency

Asynchronous programming uses an event loop to handle many concurrent operations without threads. It's great for high-concurrency I/O applications.

# ============================================================
# ASYNCHRONOUS PROGRAMMING
# ============================================================

import asyncio
import random
import time

# ============================================================
# BASIC ASYNC EXAMPLE
# ============================================================

async def async_task(task_name, delay):
    """Asynchronous task"""
    print(f"{task_name}: Starting...")
    await asyncio.sleep(delay)  # Non-blocking wait
    print(f"{task_name}: Finished after {delay}s")
    return f"{task_name} result"

async def run_async_tasks():
    """Run multiple async tasks concurrently"""
    print("Running async tasks...")
    start = time.time()
    
    # Create tasks
    tasks = [
        async_task("Task A", 2),
        async_task("Task B", 1),
        async_task("Task C", 3)
    ]
    
    # Run concurrently
    results = await asyncio.gather(*tasks)
    
    end = time.time()
    print(f"All tasks completed in {end - start:.2f}s")
    
    for result in results:
        print(result)

# ============================================================
# WEB SCRAPING WITH ASYNC
# ============================================================

async def fetch_page(url):
    """Simulate fetching a web page"""
    print(f"Fetching: {url}")
    await asyncio.sleep(random.uniform(0.5, 1.5))
    return f"Content from {url}"

async def scrape_sites():
    """Scrape multiple sites concurrently"""
    urls = [
        "example.com/page1",
        "example.com/page2",
        "example.com/page3",
        "example.com/page4",
        "example.com/page5"
    ]
    
    print(f"Scraping {len(urls)} sites...")
    start = time.time()
    
    tasks = [fetch_page(url) for url in urls]
    results = await asyncio.gather(*tasks)
    
    end = time.time()
    print(f"All sites scraped in {end - start:.2f}s")
    
    for result in results[:3]:
        print(f"  {result}")
    if len(results) > 3:
        print(f"  ... and {len(results)-3} more")

# ============================================================
# RUN ASYNC CODE
# ============================================================

print("=" * 60)
print("ASYNCHRONOUS PROGRAMMING")
print("=" * 60)

# Run async tasks
asyncio.run(run_async_tasks())

print("\n" + "=" * 40)
asyncio.run(scrape_sites())

print("""
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ ASYNCHRONOUS ADVANTAGES:                                      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ High concurrency (thousands of connections)                 β”‚
β”‚ β€’ Low overhead (no threads)                                   β”‚
β”‚ β€’ Great for I/O-bound, high-volume tasks                    β”‚
β”‚ β€’ Non-blocking operations                                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ ASYNCHRONOUS DISADVANTAGES:                                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ More complex to write                                       β”‚
β”‚ β€’ Requires async/await throughout                            β”‚
β”‚ β€’ Not for CPU-bound tasks                                    β”‚
β”‚ β€’ Learning curve is steeper                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
""")

Asynchronous key points:

  • High concurrency β€” thousands of connections
  • Low overhead β€” no threads
  • Non-blocking β€” efficient waiting
  • Complex β€” requires async/await

Quick Check: What is asynchronous programming best for? (Answer: High-concurrency I/O applications)

Method Comparison

5

Threading vs Multiprocessing vs Async

Feature Threading Multiprocessing Async
Memory Shared Separate Shared
GIL Affected Not Affected Not Affected
Best For I/O-bound CPU-bound I/O-bound (high concurrency)
Complexity Low Medium High
Overhead Low High Low
Communication Shared memory IPC Async/await

Comparison summary:

  • Threading β€” I/O-bound, simple, shared memory
  • Multiprocessing β€” CPU-bound, bypasses GIL
  • Async β€” high-concurrency I/O, non-blocking

Quick Check: Which method bypasses the GIL? (Answer: Multiprocessing)

When to Use Which

6

Choosing the Right Approach

# ============================================================
# DECISION GUIDE
# ============================================================

print("""
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ USE THREADING WHEN:                                           β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 1. Tasks are I/O-bound (network, disk, database)              β”‚
β”‚ 2. Need shared memory                                         β”‚
β”‚ 3. Low overhead is important                                  β”‚
β”‚ 4. Moderate number of concurrent tasks                        β”‚
β”‚                                                                 β”‚
β”‚ Examples: Download manager, web scraper, GUI applications      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ USE MULTIPROCESSING WHEN:                                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 1. Tasks are CPU-bound (calculations)                         β”‚
β”‚ 2. Need to use multiple CPU cores                             β”‚
β”‚ 3. Bypass the GIL                                             β”‚
β”‚ 4. Tasks are independent                                      β”‚
β”‚                                                                 β”‚
β”‚ Examples: ML training, data processing, image processing      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ USE ASYNC WHEN:                                               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 1. Very high concurrency (thousands of connections)           β”‚
β”‚ 2. I/O-bound with many small operations                       β”‚
β”‚ 3. Need low overhead                                          β”‚
β”‚ 4. Non-blocking operations                                    β”‚
β”‚                                                                 β”‚
β”‚ Examples: Web servers, chat applications, API gateways       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
""")

# ============================================================
# FLOW CHART
# ============================================================

print("=" * 40)
print("DECISION FLOW CHART")
print("=" * 40)

print("""
        Is task CPU-bound or I/O-bound?
                    |
                    v
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚                       β”‚
    CPU-BOUND              I/O-BOUND
        β”‚                       β”‚
        v                       v
    Is multicore         How many concurrent
    needed?              connections?
        β”‚                       β”‚
        v                       v
    β”Œβ”€β”€β”€β”΄β”€β”€β”€β”           β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”
    β”‚       β”‚           β”‚               β”‚
   Yes     No         Few/Medium        Many
    β”‚       β”‚           β”‚               β”‚
    v       v           v               v
Processes  β”‚        Threading         Async
           β”‚           β”‚               β”‚
           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚
                    v
            Consider hybrid approach
""")

Decision guide summary:

  • CPU-bound β†’ Multiprocessing
  • I/O-bound (few tasks) β†’ Threading
  • I/O-bound (many tasks) β†’ Async
  • Mixed β†’ Hybrid approach

Quick Check: What should you use for CPU-bound tasks? (Answer: Multiprocessing)

Real-World Example

7

Complete Multi-Tasking Application

# ============================================================
# REAL-WORLD: MULTI-TASKING APPLICATION
# ============================================================

import threading
import multiprocessing
import asyncio
import time
import random

class MultiTaskingApp:
    """Demonstrate all multi-tasking approaches"""
    
    def __init__(self):
        self.results = []
    
    # ============================================================
    # THREADING EXAMPLE
    # ============================================================
    
    def threaded_work(self, worker_id):
        """I/O-bound work using threads"""
        time.sleep(random.uniform(0.3, 0.7))
        result = f"Thread {worker_id}: completed I/O work"
        self.results.append(result)
        return result
    
    def run_threading(self, num_workers=5):
        """Run multiple threads"""
        print("\n1. THREADING:")
        threads = []
        self.results = []
        
        start = time.time()
        for i in range(num_workers):
            t = threading.Thread(target=self.threaded_work, args=(i,))
            threads.append(t)
            t.start()
        
        for t in threads:
            t.join()
        
        end = time.time()
        print(f"   Completed {num_workers} tasks in {end - start:.2f}s")
        print(f"   Results: {len(self.results)}")
    
    # ============================================================
    # MULTIPROCESSING EXAMPLE
    # ============================================================
    
    @staticmethod
    def cpu_work(n):
        """CPU-bound work"""
        result = sum(i*i for i in range(n))
        return f"Process: sum of squares = {result}"
    
    def run_multiprocessing(self, num_workers=4):
        """Run multiple processes"""
        print("\n2. MULTIPROCESSING:")
        
        start = time.time()
        with multiprocessing.Pool(processes=num_workers) as pool:
            numbers = [1000000 + i * 100000 for i in range(num_workers)]
            results = pool.map(self.cpu_work, numbers)
        
        end = time.time()
        print(f"   Completed {num_workers} CPU tasks in {end - start:.2f}s")
        for result in results[:2]:
            print(f"   {result[:50]}...")
    
    # ============================================================
    # ASYNC EXAMPLE
    # ============================================================
    
    async def async_work(self, task_id):
        """Async I/O work"""
        await asyncio.sleep(random.uniform(0.2, 0.5))
        return f"Async {task_id}: completed"
    
    async def run_async(self, num_tasks=10):
        """Run async tasks"""
        print("\n3. ASYNCHRONOUS:")
        
        start = time.time()
        tasks = [self.async_work(i) for i in range(num_tasks)]
        results = await asyncio.gather(*tasks)
        end = time.time()
        
        print(f"   Completed {num_tasks} async tasks in {end - start:.2f}s")
        print(f"   Results: {len(results)}")
    
    # ============================================================
    # RUN ALL
    # ============================================================
    
    def run_all(self):
        """Run all multi-tasking approaches"""
        print("=" * 60)
        print("MULTI-TASKING DEMONSTRATION")
        print("=" * 60)
        
        self.run_threading(5)
        self.run_multiprocessing(4)
        asyncio.run(self.run_async(10))
        
        print("\n" + "=" * 60)
        print("SUMMARY")
        print("=" * 60)
        print("""
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Approach       β”‚ Best For                    β”‚ Complexity    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Threading      β”‚ I/O-bound, moderate tasks  β”‚ Low           β”‚
β”‚ Multiprocessingβ”‚ CPU-bound, heavy tasks     β”‚ Medium        β”‚
β”‚ Async          β”‚ High-concurrency I/O       β”‚ High          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Choose based on your specific needs!
""")

# ============================================================
# RUN THE APPLICATION
# ============================================================

if __name__ == "__main__":
    app = MultiTaskingApp()
    app.run_all()

Real-world example key points:

  • All approaches β€” demonstrates threading, multiprocessing, async
  • Different use cases β€” I/O vs CPU vs high concurrency
  • Performance comparison β€” see the differences
  • Practical β€” real-world scenarios

Quick Check: What determines which multi-tasking approach to use? (Answer: The type of task - CPU-bound, I/O-bound, or high-concurrency I/O)

Best Practices

8

Multi-Tasking Best Practices

# ============================================================
# MULTI-TASKING BEST PRACTICES
# ============================================================

print("1. CHOOSE THE RIGHT APPROACH")
print("   - I/O-bound β†’ Threading or Async")
print("   - CPU-bound β†’ Multiprocessing")
print("   - Mixed β†’ Hybrid approach")

print("\n2. USE POOLS FOR MANY TASKS")
print("   - ThreadPoolExecutor for threads")
print("   - ProcessPoolExecutor for processes")
print("   - Async for high concurrency")

print("\n3. HANDLE SHARED DATA CAREFULLY")
print("   - Use locks for threads")
print("   - Use queues for processes")
print("   - Async doesn't share data")

print("\n4. LIMIT RESOURCES")
print("   - Don't create too many threads")
print("   - Don't create too many processes")
print("   - Use appropriate pool sizes")

print("\n5. HANDLE ERRORS")
print("   - Catch exceptions in threads")
print("   - Handle errors in processes")
print("   - Try/except in async tasks")

print("\n6. USE CONTEXT MANAGERS")
print("   - with Pool() as pool")
print("   - with ThreadPoolExecutor()")
print("   - Proper cleanup")

print("\n7. TEST THOROUGHLY")
print("   - Race conditions can be hard to find")
print("   - Test with different loads")
print("   - Use debugging tools")

print("\n8. MONITOR PERFORMANCE")
print("   - Measure execution time")
print("   - Check resource usage")
print("   - Optimize when needed")

Best practices summary:

  • Choose right approach β€” based on task type
  • Use pools β€” manage resources
  • Handle shared data β€” prevent race conditions
  • Test thoroughly β€” concurrency bugs are tricky

Quick Check: What should you use to manage many threads? (Answer: ThreadPoolExecutor)

Try It Yourself

Experiment with multi-tasking approaches in the editor below.

Loading Pyodide... 0%
Python Code Editor
========================================
MULTI TASKING - PRACTICE
========================================

1. SINGLE TASKING (Sequential)
----------------------------------------
Task A: Starting
Task A: Completed
Task B: Starting
Task B: Completed
Task C: Starting
Task C: Completed
Total time: 1.01s

2. THREADING (Parallel)
----------------------------------------
Starting threads in parallel...
Thread A: Starting
Thread B: Starting
Thread C: Starting
Thread C: Completed
Thread A: Completed
Thread B: Completed
Total time: 0.01s

3. MULTIPROCESSING (CPU Bound)
----------------------------------------
Running CPU tasks in parallel...
Total time: 0.40s

4. MULTI-TASKING COMPARISON
----------------------------------------
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Approach β”‚ Best For β”‚ Speed β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Single Tasking β”‚ Simple tasks β”‚ Slowest β”‚
β”‚ Threading β”‚ I/O-bound β”‚ Faster β”‚
β”‚ Multiprocessingβ”‚ CPU-bound β”‚ Fastest β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Multi-tasking makes your program faster!
πŸ†

You've Got It!

You now understand multi-tasking in Python. You know threading, multiprocessing, and async programming, and when to use each.

Quick Quiz

Test what you've learned:

1. What is multi-tasking?
2. What type of tasks are threads best for?
3. Which approach bypasses the GIL?
4. What is asynchronous programming best for?
5. What should you use for CPU-bound tasks?

Frequently Asked Questions

What is the difference between threading and multiprocessing? β–Ό

Threading uses threads that share memory and are lightweight. Multiprocessing uses separate processes with their own memory. Threads are for I/O-bound tasks; processes are for CPU-bound tasks.

What is the GIL and why does it matter? β–Ό

The Global Interpreter Lock (GIL) prevents multiple threads from executing Python bytecode at the same time. This means CPU-bound threads don't get true parallelism. Multiprocessing bypasses the GIL.

What is a common interview question about multi-tasking? β–Ό

Common questions include: "Explain the difference between threading and multiprocessing," "What is the GIL and how does it affect Python?" "When would you use async over threading?" and "How do you handle race conditions?"

Can I use multiple approaches together? β–Ό

Yes! You can use a hybrid approach. For example, use processes for CPU-bound work and threads within each process for I/O-bound tasks. This is common in data processing pipelines.

What is the easiest multi-tasking approach? β–Ό

Threading is generally the easiest to start with. The `threading` module is simple to use and works well for many I/O-bound tasks. For simple parallel tasks, `concurrent.futures.ThreadPoolExecutor` is very beginner-friendly.

Where to Go From Here

Now that you understand multi-tasking, check out these related topics:

Thread Synchronization

Learn how to safely share data between threads.

Learn More β†’

Creating Threads

Deep dive into creating and managing threads.

Learn More β†’

Threads Assignments

Practice your threading skills with exercises.

Practice Now β†’
Interview Resources
  • Python Syntax & Variables Interview Questions
  • Top SQL Interview Questions & Answers
  • SQL Joins: Displaying Data from Multiple Tables FAQ
  • Python Lists and Dictionaries Interview Questions
  • Python OOP Interview Questions
  • SQL Set Operators Interview Questions
Previous: Single Tasking Next: Thread Synchronization β†’