Understanding Asynchronous Execution: �Processes, Threads, and Asyncio
CSCI 338: Software Engineering
Fall 2025
Announcements
Agenda
Before we begin, �review the Activity Instructions and �pull down the latest files
Introduction to Asynchronous Execution
What is it?
What benefits does it provide?
Two categories of tasks to think about
CPU-Bound Tasks: Limited by the processing power of the CPU. Bottleneck: CPU resources.
�I/O-Bound Tasks: Limited by the speed of input/output operations, like reading from a disk, making network requests, or querying a database. Bottleneck: waiting for external resources.
1. Processes
Use when you want true CPU parallelism for computationally expensive tasks.
Pros:
Cons:
Demo
Let’s talk about what just happened…
When multiple processes or threads access shared data simultaneously without proper synchronization, they can interfere with each other in unexpected ways. This is called a race condition:
Result: Both processes thought they incremented the counter, but it only increased by 1 instead of 2!
Avoid race conditions by using locks
Threads: I/O Bound Tasks
Lightweight execution units sharing the same memory space.
Rule of thumb: only use if asyncio is not available
Pros:
Cons:
Asyncio and Coroutines: I/O Bound Tasks
Async I/O with coroutines (single-threaded, cooperative multitasking)
Pros:
Cons:
When to use what?
Use Processes when:
Use Asyncio when:
Use Threads when:
AsyncIO Concepts: The Event Loop
The event loop continuously monitors and manages the execution of asynchronous tasks in a program.
AsyncIO Concepts: The Event Loop
AsyncIO Concepts: Coroutines
async def prepare_drink(customer, drink):
# fake logic to prepare a drink
customers = [
("Alice", "Latte"),
("Bob", "Espresso"),
("Charlie", "Cappuccino")
]
tasks = []
for customer, drink in customers:
tasks.append(prepare_drink(customer, drink))
# Then, wait for all tasks to complete
await asyncio.gather(*tasks)
The for loop creates an array of coroutines – but does not invoke the functions yet.
await asyncio.gather(*tasks) �tells asyncio to schedule all those coroutines to run concurrently, and then wait until all of them complete.
Team Activity - 20 minutes
17