Python provides powerful tools for handling concurrency and parallelism. Two key concepts are asyncio and futures. Both help manage non-blocking operations, but they serve different purposes.
Asyncio: Asynchronous I/O
The
import asyncio
async def fetch_data():
# Perform some async I/O operation
data = await some_async_fetch()
return processed_data
async def main():
result = await fetch_data()
print(result)
asyncio.run(main())
Asyncio works by suspending and resuming coroutines instead of using OS threads. This makes it very efficient for tasks like network requests and file I/O.
The event loop handles switching between coroutines when they are suspended. So asyncio enables concurrency but not parallelism - only one coroutine runs at a time.
Futures: Managing Concurrency
A
from concurrent.futures import ThreadPoolExecutor
def blocking_operation(a, b):
# Returns after some computations
return a + b
with ThreadPoolExecutor() as executor:
f = executor.submit(blocking_operation, 1, 2)
print(f.result())
Futures abstract away thread/process details. They provide a clean API for managing and coordinating concurrent work.
So asyncio enables asynchronous I/O handling in a single thread, while futures handle parallelism across threads/processes. Together they provide powerful concurrency options.
The key difference is that asyncio avoids threads altogether, while futures use threads/processes under the hood. Asyncio works at a lower level to minimize overhead.