Python

~/victorpierre.dev ❯ cat learning/programming/python/concurrency.md

Concurrency

Python 2 min read 287 words

Concurrency runs multiple tasks in overlapping periods rather than sequentially. The payoff is mostly in I/O-bound work: file reads, network calls, database queries. Python gets there through threads, multiprocessing, or asynchronous programming.

Concurrency in Python vs. Go

Unlike Go, which has built-in support for concurrency through goroutines and channels, Python does not have a direct equivalent. However, Python provides several modules to achieve concurrency:

  1. threading Module: Used for concurrent execution of code by creating threads.
  2. multiprocessing Module: Used for concurrent execution of code by creating separate processes.
  3. asyncio Module: Used for asynchronous programming, which is especially useful for I/O-bound tasks.

Using threading Module

The threading module runs multiple threads (smaller units of a process) concurrently.

import threading
import time

def print_numbers():
    for i in range(1, 6):
        time.sleep(1)
        print(f"Number: {i}")

def print_letters():
    for letter in 'abcde':
        time.sleep(1.5)
        print(f"Letter: {letter}")

# Create threads
thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=print_letters)

# Start threads
thread1.start()
thread2.start()

# Wait for both threads to complete
thread1.join()
thread2.join()

print("Done!")

Using multiprocessing Module

The multiprocessing module runs multiple processes concurrently, the better fit for CPU-bound tasks.

import multiprocessing
import time

def print_numbers():
    for i in range(1, 6):
        time.sleep(1)
        print(f"Number: {i}")

def print_letters():
    for letter in 'abcde':
        time.sleep(1.5)
        print(f"Letter: {letter}")

# Create processes
process1 = multiprocessing.Process(target=print_numbers)
process2 = multiprocessing.Process(target=print_letters)

# Start processes
process1.start()
process2.start()

# Wait for both processes to complete
process1.join()
process2.join()

print("Done!")

Using asyncio Module

The asyncio module is for asynchronous code: coroutines that can be paused and resumed, a natural fit for I/O-bound tasks.

import asyncio

async def print_numbers():
    for i in range(1, 6):
        await asyncio.sleep(1)
        print(f"Number: {i}")

async def print_letters():
    for letter in 'abcde':
        await asyncio.sleep(1.5)
        print(f"Letter: {letter}")

async def main():
    task1 = asyncio.create_task(print_numbers())
    task2 = asyncio.create_task(print_letters())

    await task1
    await task2

asyncio.run(main())