Назад к вопросам
Middle
68
questionbank

Выполняются ли корутины в одном потоке или в нескольких?

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.