В каких случаях в Python происходит переключение контекста выполнения?

Ответ

Переключение контекста в Python зависит от модели параллелизма: многопоточности или асинхронности.

1. Многопоточность (threading)

В CPython потоки управляются операционной системой (preemptive multitasking), но Global Interpreter Lock (GIL) позволяет только одному потоку исполнять Python-байткод в один момент времени. Переключение контекста происходит, когда:

  • Поток выполняет блокирующую операцию ввода-вывода (например, чтение из сети или с диска). В этот момент он освобождает GIL, позволяя другому потоку начать выполнение.
  • Истекает квант времени, выделенный потоку. Интерпретатор принудительно приостанавливает текущий поток и передает управление другому.

2. Асинхронность (asyncio)

Асинхронность использует кооперативную многозадачность (cooperative multitasking), управляемую циклом событий (event loop). Переключение контекста происходит только в явных точках — при использовании ключевого слова await.

  • Когда программа встречает await, она передает управление обратно циклу событий.
  • Цикл событий может запустить другую задачу или дождаться завершения асинхронной операции (например, asyncio.sleep() или сетевого запроса).

Пример с asyncio:

import asyncio

async def task(name):
    print(f"Задача {name}: начало")
    # Явная точка переключения контекста.
    # Управление возвращается в event loop, который может запустить другую задачу.
    await asyncio.sleep(1)
    print(f"Задача {name}: конец")

async def main():
    # Запускаем две задачи конкурентно
    await asyncio.gather(task("A"), task("B"))

asyncio.run(main())

Вывод:

Задача A: начало
Задача B: начало
# (пауза 1 секунда)
Задача A: конец
Задача B: конец