Add some python schemes

This commit is contained in:
t0xa 2026-02-10 09:44:15 +03:00
parent 4e56f0f097
commit 62e533fec5
3 changed files with 316 additions and 0 deletions

View file

@ -0,0 +1,140 @@
@startuml
title Работа multiprocessing.Queue с большими объектами\n(2 worker процесса)
participant "Главный процесс" as Main
participant "Queue\n(pipe buffer ~65KB)" as Queue
participant "Worker 1" as W1
participant "Worker 2" as W2
== Запуск процессов ==
Main -> W1 ** : start()
Main -> W2 ** : start()
note over Main
Оба worker'а работают
параллельно в фоне
end note
== Worker 1: Отправка больших данных ==
W1 -> W1 : Обработка данных
activate W1 #lightblue
W1 -> W1 : events = [...] (большой массив)
W1 -> Queue : put({"events": events})\n[Начало сериализации]
activate Queue #orange
note right of W1
pickle сериализует объект:
ОБЪЕКТ_1 → [500 KB байт]
end note
W1 -> Queue : Запись chunk 1 (64 KB)
W1 -> Queue : Запись chunk 2 (64 KB)
note over Queue
Pipe buffer заполнен!
Больше нельзя записать
end note
W1 -[#red]> W1 : ⏸️ БЛОКИРОВКА на put()
note right of W1 #pink
Worker 1 ЖДЕТ,
пока освободится место
end note
== Worker 2: Тоже пытается отправить ==
W2 -> W2 : Обработка данных
activate W2 #lightgreen
W2 -> W2 : events = [...] (большой массив)
W2 -> Queue : put({"events": events})
W2 -[#red]> W2 : ⏸️ БЛОКИРОВКА\n(очередь занята Worker 1)
== Главный процесс: Чтение (итерация 1) ==
Main -> Main : for i in range(2):\n result = queue.get()
activate Main #yellow
Main -> Queue : get() [вызов]
note right of Main #lightgreen
Первая итерация цикла
i = 0
end note
Queue -> Queue : Читает ВСЕ байты ОБЪЕКТА_1
note over Queue
✓ Читает chunk 1 (64 KB)
✓ Читает chunk 2 (64 KB)
✓ Читает chunk 3...
...
✓ Читает последний chunk
ВАЖНО: get() не вернется,
пока не прочитает ВЕСЬ объект!
end note
Queue -> Main : return ПОЛНЫЙ ОБЪЕКТ_1
note right of Main
Получен ЦЕЛЫЙ объект
от Worker 1
end note
note over Queue #lightgreen
Pipe buffer освобожден!
Теперь Worker 1 может
продолжить запись
end note
W1 -[#green]> W1 : ✓ Разблокировка!
W1 -> W1 : put() завершен
deactivate W1
note over Queue
Теперь очередь пустая,
Worker 2 может записать
end note
W2 -[#green]> W2 : ✓ Разблокировка!
W2 -> Queue : Запись ОБЪЕКТА_2
activate Queue #orange
W2 -> W2 : put() завершен
deactivate W2
== Главный процесс: Чтение (итерация 2) ==
Main -> Queue : get() [второй вызов]
note right of Main #lightgreen
Вторая итерация цикла
i = 1
end note
Queue -> Queue : Читает ВСЕ байты ОБЪЕКТА_2
Queue -> Main : return ПОЛНЫЙ ОБЪЕКТ_2
deactivate Queue
note right of Main
Получен ЦЕЛЫЙ объект
от Worker 2
ДАННЫЕ НЕ СМЕШАЛИСЬ!
Каждый get() вернул
полный объект
end note
== Завершение ==
Main -> W1 : join()
W1 --> Main : ✓ завершен
Main -> W2 : join()
W2 --> Main : ✓ завершен
deactivate Main
note over Main, W2 #lightgreen
Все данные получены полностью
✓ Ничего не потеряно
✓ Объекты не смешались
end note
@enduml

View file

@ -0,0 +1,122 @@
@startuml gil_switching_mechanism
title GIL Switching - что происходит на микроуровне
participant "Event Loop\n(Main Thread)" as EL
participant "Python\nRuntime" as PY
participant "Worker Thread" as WT
participant "GIL" as GIL
participant "OS Kernel" as OS
== Запуск Worker Thread ==
EL -> WT: asyncio.to_thread(requests.get)
activate WT
note over EL #90EE90
Event Loop продолжает работать!
Ждёт своей очереди на GIL
end note
== Фаза 1: Worker Thread стартует (Python код) ==
WT -> GIL: Захватывает GIL
note over GIL #FFD700: Worker Thread держит GIL
WT -> WT: import requests
WT -> WT: подготовка параметров
WT -> WT: создание Request объекта
note over EL #FFD700
Event Loop ХОЧЕТ GIL,
но ждёт своей очереди
end note
PY -> PY: Прошло ~5ms или 100 bytecode инструкций
note over PY #90EE90
**GIL SWITCHING!**
Python runtime автоматически
переключает GIL между потоками
end note
PY -> WT: Отпусти GIL
WT -> GIL: Освобождает GIL (временно)
GIL -> EL: Захватывает GIL
note over EL #90EE90
Event Loop работает!
Обрабатывает задачи
end note
EL -> EL: await task1
EL -> EL: await task2
PY -> PY: Прошло ~5ms
PY -> EL: Отпусти GIL
EL -> GIL: Освобождает GIL
GIL -> WT: Захватывает GIL
note over WT
Worker Thread продолжает
подготовку к I/O
end note
== Фаза 2: Системный вызов (I/O) ==
WT -> WT: socket.connect()
note over WT #90EE90: Это системный вызов!
WT -> GIL: **Полностью освобождает GIL**
note over GIL #90EE90
🔓 GIL СВОБОДЕН!
Нет конкуренции
end note
WT -> OS: socket.recv() - ждёт данные
note over OS
Ядро читает данные
из сети
(секунды!)
end note
par Event Loop работает БЕЗ конкуренции
EL -> GIL: Захватывает GIL
EL -> EL: await task1 ✅
EL -> EL: await task2 ✅
EL -> EL: await task3 ✅
note over EL #90EE90
Полная скорость!
GIL не занят
end note
end
== Фаза 3: Данные получены ==
OS --> WT: Данные получены
WT -> GIL: Захватывает GIL опять
WT -> WT: обработка ответа (Python код)
note over WT,GIL #FFD700
Снова конкуренция за GIL
(но это быстро - десятки мс)
end note
PY -> PY: GIL switching работает
WT -> WT: возврат результата
WT --> EL: Результат готов
deactivate WT
note over EL,WT #90EE90
**Итого:**
- Фаза 1 (подготовка): ~10-50ms, GIL switching
- Фаза 2 (I/O): секунды, GIL свободен
- Фаза 3 (обработка): ~10-50ms, GIL switching
Основное время - I/O, где GIL свободен!
end note
@enduml

View file

@ -0,0 +1,54 @@
@startuml scenario2_io_with_tothread
title I/O операция С to_thread() - Event Loop свободен ✅
participant "Event Loop\n(Main Thread)" as EL
participant "Worker Thread" as WT
participant GIL
participant "OS Kernel" as OS
note over EL #90EE90: Event Loop работает
EL -> WT: asyncio.to_thread(requests.get)
activate WT
note over EL #90EE90
**Event Loop СВОБОДЕН!**
Обрабатывает другие задачи
end note
group Event Loop продолжает работу
EL -> EL: await других async задач ✅
EL -> EL: обработка новых запросов ✅
EL -> EL: работа продолжается ✅
end
group Worker Thread делает I/O
WT -> GIL: Захватывает GIL
WT -> OS: socket.recv()
note over WT,GIL #90EE90
🔓 **GIL ОСВОБОЖДАЕТСЯ**
(внутри C-кода requests)
Python интерпретатор ждёт OS
end note
note over OS
Ядро читает данные
с сетевого интерфейса
end note
OS --> WT: Данные получены
WT -> GIL: Снова захватывает GIL
end
WT --> EL: Результат готов
deactivate WT
EL -> EL: получает результат через await
note over EL,WT #90EE90
**Ключевой момент:**
Пока Worker Thread ждёт OS,
Event Loop продолжает работать!
GIL освобождается во время системных вызовов
end note
@enduml