Выполняются ли корутины в одном потоке или в нескольких?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Корутины по своей сути выполняются в одном потоке. Они реализуют кооперативную многозадачность, где переключение между задачами происходит явно, когда корутина "отдает" управление с помощью ключевого слова await. В отличие от потоков, где операционная система управляет переключением, в корутинах это делает программа.
Однако, корутины могут использовать пулы потоков или процессов для выполнения блокирующих операций (например, ввод/вывод), чтобы не блокировать основной цикл событий. В таком случае, сама блокирующая операция будет выполняться в другом потоке/процессе, но ожидание ее результата происходит в том же потоке, где работает цикл событий с корутинами.
Ключевые отличия:
| Признак | Потоки (Threads) | Корутины (Coroutines) |
|---|---|---|
| Управление | Операционная система (преemptive) | Программа (cooperative) |
| Параллелизм | Истинный параллелизм (на многоядерных) | Конкурентность (один поток) |
| Переключение | Дорого (контекстное переключение ОСs) | Дешево (передача управления) |
| Использование | Блокирующие операции, CPU-bound задачи | Неблокирующие операции, I/O-bound задачи |
| Создание | Дорого | Дешево |
| Память | Больше | Меньше |
Пример асинхронной функции с использованием asyncio:
import asyncio
async def fetch_data(delay):
// Имитация асинхронной операции
print(f"Начинаю получать данные (задержка {delay} сек)")
await asyncio.sleep(delay)
print(f"Данные получены через {delay} сек")
return f"Данные после {delay} сек"
async def main():
// Запускаем несколько корутин
task1 = asyncio.create_task(fetch_data(2))
task2 = asyncio.create_task(fetch_data(1))
// Ожидаем завершения корутин
result1 = await task1
result2 = await task2
print(f"Результаты: {result1}, {result2}")
if __name__ == "__main__":
// Запускаем main корутину в цикле событий
asyncio.run(main())
В данном примере fetch_data является корутиной. await asyncio.sleep(delay) передает управление циклу событий, позволяя выполнять другие задачи (в данном случае, другую корутину fetch_data с задержкой 1 секунда) в том же потоке, пока ожидается завершение "сна".
Таким образом, корутины сами по себе не создают новые потоки, но они отлично подходят для эффективного управления конкурентностью задач в рамках одного потока, особенно для I/O-bound операций, где нет интенсивного использования CPU.