Ответ
Переключение контекста в 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: конец