Sobes.tech
Junior
214

What is concurrency?

Answer from AI

sobes.tech AI

Method of performing multiple tasks that may overlap in time.

  • Parallelism: Tasks are executed simultaneously on different CPU cores.
  • Concurrency: Tasks may be executed sequentially or interleaved on a single core, creating an illusion of simultaneity.

In Python, concurrency is often implemented using:

  • Threads: Used for I/O operations (network, disk I/O), where a thread can "sleep" while waiting, allowing another thread to work. Due to GIL (Global Interpreter Lock), threads do not provide true parallelism for CPU-bound tasks in standard CPython.
  • Processes: Used for CPU-bound tasks. Each process has its own independent address space, bypasses GIL, and provides true parallelism.
  • Coroutines and Asynchronous Programming (asyncio): Lightweight tasks that cooperatively switch. Ideal for high-load I/O-bound applications.
Mechanism Usage Parallelism (CPU-bound) GIL (CPython) Switching Resource Costs
Threads I/O-bound No (due to GIL) Affects OS scheduler High
Processes CPU-bound, I/O-bound Yes Bypassed OS scheduler Very high
Coroutines I/O-bound, High-load No No impact Explicit (await) Low
# Example of using threads for an I/O-bound task
import threading
import time

def download_data(url):
    # Simulate network request
    print(f"Starting download from {url}")
    time.sleep(2) # Simulate I/O wait
    print(f"Download from {url} completed")

urls = ["http://site1.com", "http://site2.com", "http://site3.com"]
threads = []

for url in urls:
    thread = threading.Thread(target=download_data, args=(url,))
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join() # Wait for all threads to finish

print("All downloads completed.")
# Example of using processes for CPU-bound tasks
import multiprocessing
import time

def calculate_square(number):
    # Simulate CPU-bound calculation
    print(f"Starting calculation of square for {number}")
    result = number * number
    time.sleep(1) # Simulate CPU work
    print(f"Square of {number} - {result}")
    return result

numbers = [1, 2, 3, 4]
pool = multiprocessing.Pool(processes=2) # Use 2 processes

results = pool.map(calculate_square, numbers)

pool.close()
pool.join()

print(f"All calculations finished. Results: {results}")
# Example of using asyncio for I/O-bound tasks
import asyncio

async def download_data_async(url):
    # Simulate asynchronous network operation
    print(f"Starting async download from {url}")
    await asyncio.sleep(2) # Simulate async I/O wait
    print(f"Async download from {url} completed")

async def main():
    urls = ["http://site1.com", "http://site2.com", "http://site3.com"]
    tasks = [download_data_async(url) for url in urls]
    await asyncio.gather(*tasks) # Run tasks concurrently (cooperatively)

print("Starting async downloads...")
asyncio.run(main())
print("All async downloads completed.")

Concurrency allows efficient resource utilization, especially when involving I/O operations, avoiding CPU idle time.