← Назад к вопросам
Может ли одна корутина отдать управление другой корутине?
2.7 Senior🔥 201 комментариев
#Асинхронность и многопоточность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Может ли одна корутина отдать управление другой корутине
Да, может! Это основная идея asyncio. Корутины передают управление друг другу через await.
Как корутины передают управление
await - это точка, где текущая корутина временно останавливается и позволяет другой работать.
import asyncio
async def coroutine_a():
print("A: начало")
await asyncio.sleep(1)
print("A: конец")
async def coroutine_b():
print("B: начало")
await asyncio.sleep(1)
print("B: конец")
async def main():
await asyncio.gather(
coroutine_a(),
coroutine_b()
)
asyncio.run(main())
Механизм: await передаёт управление
Когда ты пишешь await что-то, ты говоришь:
- Я приостанавливаюсь здесь
- Другие корутины могут работать
- Когда что-то будет готово, разбуди меня
async def fetch_user(user_id):
response = await http_client.get(f'/users/{user_id}')
return response.json()
async def main():
results = await asyncio.gather(
fetch_user(1),
fetch_user(2),
fetch_user(3)
)
Явное отдание управления
async def task_a():
for i in range(3):
print(f"A: {i}")
await asyncio.sleep(0)
async def task_b():
for i in range(3):
print(f"B: {i}")
await asyncio.sleep(0)
asyncio.run(asyncio.gather(task_a(), task_b()))
Что происходит БЕЗ await?
Если не используешь await, управление НЕ передаётся!
async def task_a():
for i in range(3):
print(f"A: {i}")
async def task_b():
for i in range(3):
print(f"B: {i}")
asyncio.run(asyncio.gather(task_a(), task_b()))
# task_a полностью закончилась перед task_b!
Параллельное выполнение vs последовательное
import asyncio
import time
async def slow_task(name, duration):
print(f"{name} начал ({duration}s)")
await asyncio.sleep(duration)
print(f"{name} готов")
async def sequential():
start = time.time()
await slow_task("Task1", 2)
await slow_task("Task2", 2)
await slow_task("Task3", 2)
print(f"Время: {time.time() - start:.1f}s")
async def parallel():
start = time.time()
await asyncio.gather(
slow_task("Task1", 2),
slow_task("Task2", 2),
slow_task("Task3", 2)
)
print(f"Время: {time.time() - start:.1f}s")
Event Loop - дирижер оркестра
Event loop управляет всеми корутинами:
- Запускает task1
- task1 встречает await -> приостанавливается
- Запускает task2
- task2 встречает await -> приостанавливается
- Ждёт когда обе готовы
- Возобновляет обе
import asyncio
async def task1():
print("Task1: работаю")
await asyncio.sleep(0.1)
print("Task1: готов")
async def task2():
print("Task2: работаю")
await asyncio.sleep(0.1)
print("Task2: готов")
async def main():
await asyncio.gather(task1(), task2())
asyncio.run(main())
Проблема: blocking без await
import asyncio
import time
async def blocking_task():
print("Начало")
time.sleep(2) # БЛОКИРУЕТ весь event loop!
print("Конец")
async def other_task():
for i in range(3):
print(f"Other: {i}")
await asyncio.sleep(0.1)
async def main():
await asyncio.gather(blocking_task(), other_task())
Other не мог работать пока blocking_task спал!
Решение: executor для blocking кода
import asyncio
import time
async def blocking_task():
print("Начало")
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, time.sleep, 2)
print("Конец")
async def other_task():
for i in range(3):
print(f"Other: {i}")
await asyncio.sleep(0.1)
async def main():
await asyncio.gather(blocking_task(), other_task())
asyncio.run(main())
Контекстные переменники
import asyncio
from contextvars import ContextVar
request_id = ContextVar('request_id', default='no-id')
async def process(name):
rid = request_id.get()
print(f"{name} начал с request_id={rid}")
await asyncio.sleep(0.1)
print(f"{name} завершился")
async def main():
token1 = request_id.set('req-1')
task1 = asyncio.create_task(process('Task1'))
token2 = request_id.set('req-2')
task2 = asyncio.create_task(process('Task2'))
await asyncio.gather(task1, task2)
asyncio.run(main())
Каждая корутина имеет свой контекст!
Ожидание завершения конкретной корутины
async def producer():
for i in range(3):
print(f"Producing {i}")
await asyncio.sleep(0.1)
async def consumer():
print("Consuming")
await asyncio.sleep(0.5)
async def main():
await asyncio.gather(producer(), consumer())
Заключение
- Корутины передают управление через await
- Event loop управляет всеми корутинами
- asyncio.gather() запускает параллельно
- Без await нет передачи управления
- Используй async/await для масштабируемых I/O приложений
Основная идея: одна корутина ждёт (await), другие продолжают работать. Это однопоточная модель параллелизма, но очень эффективная для I/O операций.