关于Python 3.6中Asyncio并发原理及代码实现的疑问
Hey there! Let's break down where your understanding of asyncio might be off, and why your code is running synchronously instead of concurrently.
First, let's clarify a core point: asyncio uses a single-threaded event loop. When you await something, the current coroutine pauses only if the thing you're awaiting is an asynchronous operation that yields control back to the event loop. If the operation doesn't yield control (like a blocking sync function), the event loop can't switch to other coroutines—so everything runs one after another.
Your initial thought is partially right: await does pause the current coroutine, but only when it's waiting on something that lets the event loop do other work. If you're awaiting a blocking task, the loop gets stuck waiting for that task to finish before moving on.
Chances are, your code falls into one of two common traps:
- You're
awaiting a synchronous blocking function (liketime.sleep(), or a sync database call) instead of its async equivalent. - You're awaiting coroutines one after another in sequence, instead of launching them as concurrent tasks.
For example, here's a typical "broken" version that runs synchronously:
import asyncio import time async def slow_task(name): print(f"Starting {name}") time.sleep(2) # This is a BLOCKING sync call! It doesn't yield control. print(f"Finishing {name}") async def main(): # Awaiting one task at a time forces sequential execution await slow_task("Task 1") await slow_task("Task 2") await slow_task("Task 3") asyncio.run(main())
This code will take 6 seconds total, because each time.sleep(2) blocks the entire event loop—no other coroutines can run while it's sleeping.
To make it work as expected, you need two changes:
- Replace blocking sync operations with async alternatives (like
asyncio.sleep()instead oftime.sleep()). - Launch multiple coroutines as concurrent tasks so the event loop can switch between them.
Here's the corrected version:
import asyncio async def slow_task(name): print(f"Starting {name}") await asyncio.sleep(2) # Async sleep yields control to the event loop print(f"Finishing {name}") async def main(): # Use asyncio.gather() to run tasks concurrently await asyncio.gather( slow_task("Task 1"), slow_task("Task 2"), slow_task("Task 3") ) # Alternatively, create tasks explicitly first: # task1 = asyncio.create_task(slow_task("Task 1")) # task2 = asyncio.create_task(slow_task("Task 2")) # task3 = asyncio.create_task(slow_task("Task 3")) # await task1 # await task2 # await task3 asyncio.run(main())
This code will take only 2 seconds total—all three tasks start at nearly the same time, and when each hits await asyncio.sleep(2), it yields control back to the event loop, which can run the other tasks until their sleep is done.
awaitpauses the current coroutine only when the awaited object is an async operation that yields control. Blocking sync code won't let this happen.- To run coroutines concurrently, don't await them one after another—use
asyncio.gather()orasyncio.create_task()to schedule them all at once. - Asyncio's concurrency is about cooperative multitasking: coroutines have to voluntarily give up control (via
awaiting async operations) for the event loop to switch to other work.
内容的提问来源于stack exchange,提问作者N Fembrianto

