РозробкаБудь-який рівень

Python

Python — мова загального призначення, чий стандартний інтерпретатор виконує код Python в одному потоці за раз, а важкі обчислення лишає скомпільованим бібліотекам. Саме через це блокування, GIL, чотири потоки рідко бувають учетверо швидшими, вебсервери на Python працюють кількома процесами, а повільний сервіс потребує діагнозу до лікування: він чекає чи обчислює? Сторінка починається з дванадцяти навантажень і інструмента, що справді пришвидшує кожне; далі — GIL і нова збірка без нього, asyncio, версії й щорічний реліз, типи й пакування, вебсервери та їхня пам’ять, п’ять задокументованих кейсів і те, де все це вироджується.

Поточна версія
3.14 · 3.15 — 1 жовт. 2026
Модель
Python виконує один потік за раз
Підтримка
5 років: 2 — виправлення, 3 — безпека

Чекає чи обчислює? Дванадцять навантажень і те, що допомагає

Кожне питання продуктивності в Python починається з того самого діагнозу. Програма повільна тому, що чекає, — на мережу, диск, базу даних, — чи тому, що обчислює? На графіку латентності ці два випадки виглядають однаково. У Python вони лікуються протилежно, бо стандартний інтерпретатор дає виконувати код Python лише одному потоку за раз. Робота, що чекає, добре розходиться по потоках; обчислення, написані на Python, не розходяться зовсім. Ось дванадцять поширених навантажень, діагноз для кожного і те, що справді допомагає. Наступні розділи посилаються на рядки за номерами.

#НавантаженняЧекає чи обчислюєЧи допоможуть потоки?Що справді допомагає
1500 викликів зовнішнього APIЧекаєТакasyncio з асинхронним клієнтом або пул потоків
2В’юха Django, що чекає на базу данихЧекаєТак — але скільки, вирішує вебсерверБільше воркерів сервера або потоки в кожному (gthread)
3Завантаження чи читання 10 000 файлівЧекаєТакThreadPoolExecutor
4requests.get() чи time.sleep() усередині async defЧекає — в єдиному потоці циклуНі: це зупиняє кожну іншу корутинуАсинхронний клієнт або asyncio.to_thread()
5Цикл на чистому Python по 10 мільйонах рядківОбчислює, на PythonНіОдна операція над масивом у NumPy, pandas чи Polars або пул процесів
6Розбір CSV-файлу на 2 ГБОбчислюєНе з модулем csvЧитач, написаний на C чи Rust, — pandas, Polars, pyarrow
7Множення великих матриць NumPyОбчислює, на CНе потрібно — бібліотека вже займає всі ядраНічого; обмежте потоки бібліотеки, коли запускаєте ще й кілька процесів
8Зміна розміру зображень у PillowОбчислює, на CЧасто — багато операцій звільняють блокуванняПотоки, а для великих пакетів — процеси
9Інференс моделі в PyTorchОбчислює, на C++ чи на GPUБібліотека сама звільняє блокуванняГрупуйте запити; один процес на GPU
10Робота на чистому Python, що має зайняти всі ядра в одному процесіОбчислює, на PythonЛише на збірці без GILpython3.14t, якщо кожне розширення це підтримує; інакше процеси
11Утиліта командного рядка, що стартує дві секундиІмпорт модулівНіpython -X importtime, потім ліниві імпорти (3.15)
12API, де перетворення об’єктів на відповідь забирає більшість часуОбчислює, на PythonНіСкомпільований серіалізатор — orjson або Pydantic 2, чиє ядро написано на Rust

GIL і збірка без нього

CPython, стандартний інтерпретатор, захищає свої нутрощі одним блокуванням — глобальним блокуванням інтерпретатора, GIL. Потік має тримати його, щоб виконувати байт-код Python. Потоки справжні, потоки операційної системи, і плануються звичайно, але Python виконує лише той, хто тримає блокування. Типово кожні 5 мілісекунд власника просять його відпустити, щоб інші отримали свою чергу; який потік піде наступним, обирає операційна система. Запустіть три потоки рахувати числа на машині з трьома вільними ядрами — і отримаєте пропускну здатність одного ядра плюс ціну перемикань.

Байт-код Python одночасно виконує лише один потік, тож три потоки з навантаженням на CPU по черзі працюють на одному ядрі, скільки б ядер не мала машина, — у лівій панелі в кожному стовпці заповнено один проміжок. Три процеси мають власний інтерпретатор і власне блокування, тож їхні проміжки заповнені всі. Виняток і є причиною тримати потоки: потік, що чекає на сокет, файл чи базу даних, віддає блокування на час очікування, тож робота з вводом-виводом справді накладається.

Друга половина правила й лишає потоки корисними. Потік, що чекає — на сокет, файл, відповідь бази даних, — на час очікування звільняє блокування, і так само роблять добре написані C-розширення під час довгої роботи: NumPy, pandas, PyTorch, драйвери баз даних. Це рядки 1–3 і 7–9. Саме блокування існує через те, як CPython керує пам’яттю. Кожен об’єкт має лічильник посилань, що змінюється щоразу, коли щось починає чи перестає його використовувати. Два потоки, що водночас змінюють той самий лічильник, зіпсують його, а одне велике блокування робило кожен лічильник безпечним майже без витрат для програми з одним потоком.

Збірка без GIL

Прибрати блокування — означає зробити кожен лічильник посилань і кожен вбудований тип безпечним інакше. PEP 703 описав як, і впроваджують це поетапно. Python 3.13, у жовтні 2024 року, вийшов з окремою експериментальною збіркою без GIL. Python 3.14, у жовтні 2025-го, зробив цю збірку офіційно підтримуваною, хоч і досі необов’язковою та окремою: ви ставите python3.14t поруч зі звичайним інтерпретатором. Ціна для однопотокового коду тепер «приблизно 5–10%», за нотатками до релізу, — значно менше, ніж у 3.13. Python 3.15 додає стабільний двійковий інтерфейс для збірок без GIL, тож бібліотека може постачати один скомпільований пакет для кількох версій. Зробити збірку без GIL типовою — окреме рішення, і дати в нього немає.

Підступ — у розширеннях. C-розширення має оголосити, що воно безпечне без блокування. Якщо ви імпортуєте таке, що не оголосило, інтерпретатор без GIL вмикає блокування знову для всього процесу й друкує попередження — тож одна стара залежність тихо повертає вас до стандартної поведінки. Перш ніж переносити рядок 10 на python3.14t, перевірте кожну скомпільовану залежність, а не лише власний код.

ВаріантЩо виконується паралельноЧого це коштуєДля чого брати
Потоки, стандартна збіркаОчікування і C-код, що звільняє блокуванняНебагато; пам’ять спільнаРядки 1–3 і 7–9
Процеси — пул процесів, кілька воркерів сервераУсеПам’ять цілого інтерпретатора на кожен; дані копіюються між нимиОбчислення на Python сьогодні
Субінтерпретатори — concurrent.interpreters, 3.14Код Python, по блокуванню на інтерпретаторЖодних спільних об’єктів; багато розширень ще не підтримуютьсяІзольовані обчислювальні задачі в межах одного процесу
Збірка без GIL — python3.14tКод Python у звичайних потокахБлизько 5–10% на однопотоковому коді; кожне розширення має це підтримуватиРядок 10, коли залежності готові

asyncio: один потік і три способи його зупинити

asyncio — відповідь стандартної бібліотеки на рядки 1–3: цикл подій () в одному потоці, що виконує багато корутин по черзі. Корутина — функція, оголошена через async def, — виконується, доки не дійде до await на чомусь неготовому, віддає керування циклу й відновлюється, коли приходить відповідь. Так в одному потоці можуть бути в польоті десять тисяч з’єднань. До нього часто тягнуться як до загального пришвидшення, а це не воно. Він накладає очікування; обчисленням він не допомагає нічим. І він залежить від того, що кожен шматок коду співпрацює, — саме тут він і ламається.

Перший спосіб зупинити його — рядок 4. Блокуючий виклик — requests.get(), time.sleep(), класичний драйвер бази даних — ніколи не повертає керування. Єдиний потік циклу сидить усередині нього, і кожна інша корутина чекає, хоч би якою готовою була її власна відповідь. Одна бібліотека без підтримки async здатна перекреслити весь задум, і це найчастіша причина, чому asyncio-сервіс виявляється повільнішим за багатопотоковий, який він замінив.

asyncio виконує кожну корутину в одному потоці, а корутина віддає потік лише на await. Блокуючий виклик на кшталт requests.get його не віддає ніколи, тож поки віддалений сервіс відповідає, кожен інший запит у циклі чекає — навіть ті, чия власна робота триває десять мілісекунд. Await на асинхронному клієнті натомість звільняє цикл на час очікування, і швидкі запити завершуються майже одразу. Час умовний.
Усередині `async def` це блокує циклНатомість
requests.get()httpx.AsyncClient або aiohttp
time.sleep()await asyncio.sleep()
psycopg2 та інші класичні драйвери баз данихpsycopg 3 в асинхронному режимі, asyncpg
SDK без асинхронної версіїawait asyncio.to_thread(call, …) — виклик іде в робочому потоці
Читання чи запис великого файлуТак само asyncio.to_thread()
Важкі обчислення (рядки 5, 6, 12)loop.run_in_executor() з пулом процесів

Другий спосіб губить роботу без жодної помилки. asyncio.create_task() запускає корутину у фоні, а документація містить попередження, яке більшість ніколи не читає: «Цикл подій тримає на задачі лише слабкі посилання. Задачу, на яку немає посилань деінде, може будь-коли прибрати збирач сміття — навіть до її завершення». Задача «запустив і забув» — надіслати лист, записати аудит — може просто зникнути. Тримайте посилання на кожну задачу або запускайте їх усередині asyncio.TaskGroup (Python 3.11), що чекає на всі й скасовує решту, якщо одна впала.

Третій спосіб — очікування без кінця. Корутина, що чекає на сервіс, який ніколи не відповість, назавжди займає своє місце в циклі, і коли таких набирається досить, сервісу бракує з’єднань чи пам’яті. Обгортайте кожен зовнішній виклик в asyncio.timeout() (теж 3.11) або задавайте клієнту власний тайм-аут.

Версії: одна на рік, п’ять років кожна

Нова версія Python виходить щожовтня. Вона отримує два роки виправлень помилок — 18 місяців для версій до 3.13, — далі лише виправлення безпеки, до п’яти років від релізу, а потім — нічого. Python 2 дійшов до цієї точки 1 січня 2020 року, після того як дату його кінця вже відсунули на п’ять років. Таблиця перелічує, що кожна недавня версія додала такого, що ви зустрінете в коді, і коли закінчуються її виправлення безпеки.

ВерсіяВипущеноЩо ви зустрінете в кодіПатчі безпеки до
3.9жовт. 2020Злиття dict через |, list[int] без імпорту, zoneinfoЗавершено жовт. 2025
3.10жовт. 2021Інструкція match, X | None у підказках типів, зрозуміліші повідомлення про помилкиЖовт. 2026 — цього місяця
3.11жовт. 2022У середньому в 1,25 раза швидший, except*, asyncio.TaskGroup, tomllibжовт. 2027
3.12жовт. 2023Псевдоніми type і синтаксис узагальнень, f-рядки, що можуть повторювати лапки, distutils прибраножовт. 2028
3.13жовт. 2024Експериментальні збірка без GIL і JIT, нова інтерактивна оболонка, cgi і telnetlib прибраножовт. 2029
3.14жовт. 2025Підтримувана збірка без GIL, шаблонні рядки t"…", анотації, що обчислюються на вимогу, concurrent.interpreters, Zstandardжовт. 2030
3.15Заплановано 1 жовт. 2026UTF-8 за замовчуванням, явні ліниві імпорти, frozendict, семплювальний профайлер Tachyonжовт. 2031

Типи й пакування: хай перевіряє машина

Python перевіряє типи, коли виконує код, а не коли ви його зберігаєте. Саме це робить його швидким у написанні — і саме це робить велику кодову базу ризикованою: помилка в назві атрибута стає AttributeError у продакшені, а не червоним підкресленням. Відповіддю, на якій мова зупинилася, стали підказки типів: анотації, які інтерпретатор ігнорує, а перевіряч читає, щоб знайти помилку до релізу. mypy — перший перевіряч, Pyright стоїть за більшістю редакторів, а ty від Astral з’явився як бета в грудні 2025 року. Підказки поступові: анотуйте межі модуля сьогодні, його нутрощі наступного місяця — і підвищуйте суворість перевіряча свідомо.

Там, де дані входять у систему, самих підказок замало: підказка каже, що має прийти, а не що прийшло. Pydantic закриває цей розрив, перевіряючи й приводячи реальні дані до анотації під час виконання, — тому він і лежить під FastAPI та більшістю сучасного Python-коду для . Запускайте статичний перевіряч у збірці, валідуйте на межі — і дайте типам описувати все, що між ними.

Пакування — друга річ, яку треба зробити правильно рано, бо його збої тихі. Кожен проєкт отримує власне віртуальне середовище — сучасні дистрибутиви Linux узагалі відмовляються робити pip install у системний Python, з помилкою «externally-managed-environment». Залежності оголошують у pyproject.toml, а точні розв’язані версії лягають у файл блокування, який комітять. Без нього двоє розробників і сервер збірки працюють із трьома різними наборами залежностей, і різниця виявляється як баґ, якого ніхто не може відтворити. Кожен інструмент мав власний формат такого файлу; з березня 2025 року є стандартний — pylock.toml.

ЗадачаКласичні інструментиПоширене у 2026
Встановити, розв’язати й зафіксувати залежностіpip з pip-tools, Poetryuv, Poetry
Віртуальні середовища й версії Pythonvenv, virtualenv, pyenvuv
Лінтинг і форматуванняflake8, isort, BlackRuff
Перевірка типівmypymypy, Pyright, ty (бета)

uv, Ruff і ty походять від однієї компанії, Astral, і написані на Rust — здебільшого тому вони в десять-сто разів швидші за інструменти, які замінюють. У березні 2026 року Astral оголосила, що погодилася приєднатися до OpenAI, і заявила, що інструменти лишаться відкритими. Це привід спиратися на стандарти — pyproject.toml, pylock.toml, звичайні віртуальні середовища, — а не на приватні можливості одного інструмента, щоб перехід лишався дешевим.

Два індекси, одне ім’я

Компанії часто публікують внутрішні пакети в приватний індекс і додають його через --extra-index-url поруч із публічним — PyPI. Пастка в тому, як обирає pip. Він не віддає переваги вашому індексу. Він «об’єднує версії-кандидати з усіх індексів і обирає найкращу з об’єднаного набору», словами документації uv. Тож якщо хтось опублікує на PyPI пакет із тим самим ім’ям і вищим номером версії, pip поставить саме його — і виконає його код. Це називається dependency confusion. Типова поведінка uv протилежна: використовується лише перший індекс, у якому є це ім’я. Ця поведінка існує через кейс, зображений на схемі.

Коли приватний індекс додано поруч із PyPI через --extra-index-url, pip об’єднує версії-кандидати з усіх індексів і ставить найкращу, тож кожен, хто опублікує на PyPI те саме ім’я з вищою версією, отримає свій код встановленим і запущеним. Це називається dependency confusion. Типово uv бере ім’я лише з першого індексу, де воно є. Номери версій умовні; кейс, що стоїть за типовою поведінкою uv, — інцидент із torchtriton у грудні 2022 року.

Django, FastAPI і сервер під ними

Два фреймворки покривають більшість серверного Python, і побудовані вони на протилежних припущеннях, а не є конкурентами різного рівня якості. Django дає повний застосунок — , міграції, автентифікацію, адмінку, форми, шаблони — і очікує, що ви будуватимете всередині нього. FastAPI дає маршрутизацію, валідацію й документацію і очікує, що решту ви оберете самі. Flask досі лишається розумним мінімальним вибором; більшість нової роботи над API йде у FastAPI, бо валідація й згенерована схема беруться з тих самих підказок типів, які ви й так писали.

Django

  • Усе в комплекті: адмінка, автентифікація, ORM і міграції є вже першого дня.
  • Синхронний за природою; асинхронні в’юхи є, а ORM асинхронний лише частково.
  • Поточний — 6.1; — 5.2, з патчами до квітня 2028 року.
  • Ризик — «товста модель», що росте, доки бізнес-правила можна перевірити лише через в’юхи.

FastAPI

  • Асинхронний за задумом, на ASGI — природно пасує сервісам, що здебільшого чекають на інші сервіси.
  • Валідація й документація OpenAPI генеруються з ваших підказок типів.
  • Досі має версії 0.x, тож читайте нотатки до релізу перед кожним оновленням.
  • Ризик — збирати власний стек: ORM, міграції, автентифікацію, адмінку — по одному рішенню за раз.

Модель релізів Django теж змінюється. Сьогодні функціональний реліз виходить кожні вісім місяців, і лише кожен третій — довгостроковий. Наступний такий, 6.2, очікується у квітні 2027 року з підтримкою до квітня 2030-го. З січня 2028 року Django переходить на один реліз на рік із номером за роком — Django 2028, — і кожен реліз отримує ті самі три роки підтримки.

Жоден із фреймворків не запускає себе в продакшені сам. Застосунок Django працює під WSGI-сервером на кшталт Gunicorn; застосунок FastAPI — під ASGI-сервером на кшталт Uvicorn, часто як воркери Gunicorn. Кількість воркерів цього сервера — справжня межа паралельності, і через GIL корисна конфігурація — кілька процесів-воркерів, а не багато потоків в одному. Документація Gunicorn радить починати з «(2 × ядра ) + 1» і попереджає, що йому «зазвичай потрібно лише 4–12 воркерів». Кількість зазвичай обмежує пам’ять, а не ядра, — і тому варто знати, скільки пам’яті воркери насправді ділять.

Чому воркери ділять менше пам’яті, ніж мали б

Сервер із попереднім форком завантажує застосунок один раз у головному процесі, а потім форкає його у воркери. У Linux дочірній процес після форку спершу ділить із батьківським кожну сторінку пам’яті; сторінку копіюють лише тоді, коли в неї пише одна зі сторін. Це copy-on-write, і завдяки йому двадцять воркерів мали б коштувати трохи більше за одного. Python ламає це двома способами. Читання об’єкта змінює його лічильник посилань — це запис у заголовок об’єкта, — тож саме використання спільних об’єктів копіює сторінки, на яких вони лежать. А прохід збирача сміття торкається кожного відстежуваного об’єкта, тож один прохід може скопіювати більшість спільної пам’яті одразу.

Сервер із попереднім форком завантажує застосунок один раз і форкає воркери, що ділять його сторінки пам’яті, доки одна зі сторін не запише в сторінку. Python пише під час читання: використання об’єкта змінює його лічильник посилань, тож сторінки, де він лежить, копіюються у воркер. Прохід збирача сміття пише в кожен відстежуваний об’єкт і може за раз скопіювати майже всю спільну пам’ять. Виклик gc.freeze перед форком тримає збирач подалі від об’єктів головного процесу; з 3.12 безсмертні об’єкти на кшталт None і малих цілих чисел ніколи не змінюють лічильників. Кількість сторінок умовна.

Саме з цієї проблеми вийшли два виправлення. gc.freeze(), доданий у 3.7, переносить кожен об’єкт, що існує на момент виклику, у постійне покоління, яке збирач більше ніколи не відвідує: викличте gc.disable() рано в головному процесі, gc.freeze() — просто перед форком, і gc.enable() — у кожному воркері. А з 3.12 деякі об’єкти безсмертні — None, малі цілі числа, інтерновані рядки, — тож їхні лічильники посилань більше не змінюються. Щоб побачити, чи це важить для вас, порівняйте спільну й приватну пам’ять воркера в /proc/<pid>/smaps_rollup за хвилину після старту й за годину.

П’ять кейсів і те, чого в кожному бракувало

Кожен кейс задокументували ті, з ким він стався: власні записи релізів Python, інженерні блоги, повідомлення проєкту про інцидент, бюлетень безпеки. Разом вони покривають мову, пам’ять, пакування, файли даних і гроші за інтерпретатором.

КейсЩо сталосяЧого бракувало
Python 2 → 3, 2008–2020Розрив у тому, як працюють текст і байти, завершувався дванадцять роківСпосіб запускати одну кодову базу на обох версіях із першого дня
Instagram, січ. 2017Воркери за секунди після старту втрачали третину спільної пам’ятіЗбирання сміття, що не чіпає об’єкти батьківського процесу
torchtriton, груд. 2022Пакет на PyPI з ім’ям приватної залежності крав файли в користувачів нічних збірокІнсталятор, що тримається індексу, якому належить ім’я
Моделі в pickle, 2024–2025Близько сотні файлів моделей на Hugging Face виконували код під час завантаженняФормат ваг, що не може виконувати код
Faster CPython, 2021–2025План пришвидшення вп’ятеро, досягнуто 1,25×, потім фінансування команди припинилосяФінансування, не прив’язане до одного роботодавця

Перший кейс — найдовша міграція, якої велика мова вимагала від своїх користувачів. Python 3.0, випущений 3 грудня 2008 року, змінив те, що таке рядок: текст став Unicode, а байти — окремим типом, тож код, що їх змішував, — тобто більшість коду, що торкався файлів чи мережі, — треба було переписати, і він не міг легко працювати на обох версіях. Кінець Python 2.7 призначили на 2015 рік, а потім відсунули на п’ять років; підтримка припинилася 1 січня 2020-го, а останній реліз, 2.7.18, вийшов у квітні 2020 року. Dropbox, чий десктопний клієнт мав понад мільйон рядків Python, почав перехід у 2015 році й закінчив у 2018-му, постачаючи обидва інтерпретатори поруч і поступово перемикаючи користувачів. Того, що зрештою зробило такі переходи можливими, — коду, написаного для обох версій, а потім перевірячів типів, що знаходили зламане, — на старті не існувало. Мова може змінити свої основи раз на покоління і платить за це роками.

Третій кейс — схема з розділу про пакування, лише наживо. Нічні збірки PyTorch залежали від пакета torchtriton, опублікованого у власному індексі PyTorch. До грудня 2022 року пакета з таким ім’ям на PyPI не існувало. Потім хтось його завантажив, і між 25 і 30 грудня 2022 року кожен, хто ставив нічну збірку в Linux через pip, отримував копію з PyPI — «оскільки індекс PyPI має перевагу», як сказано в повідомленні PyTorch. Імпорт запускав бінарник, що зчитував ім’я машини, змінні середовища, /etc/passwd, усе в ~/.ssh і першу тисячу файлів у домашній теці й відправляв їх назовні через DNS-запити. PyTorch перейменував залежність на pytorch-triton, зареєстрував це ім’я на PyPI, щоб його не зайняв ніхто інший, і прибрав уражені збірки. Стабільних релізів це не торкнулося.

П’ятий кейс — про те, хто платить за те, щоб інтерпретатор ставав швидшим. У 2020 році Марк Шеннон опублікував план зробити CPython приблизно вп’ятеро швидшим за чотири етапи, кожен приблизно на 50%, і з 2021 року Microsoft фінансувала невелику команду разом із Гвідо ван Россумом, щоб його виконати. Робота була справжньою: 3.11, за нотатками до релізу, став у середньому в 1,25 раза швидшим, а в 3.13 з’явився експериментальний . У травні 2025 року Microsoft припинила підтримку проєкту й звільнила більшість команди — напередодні мовного саміту на PyCon. Уже злиті покращення лишаються в кожному релізі; пізніші етапи плану втратили головних інженерів. Мова, якою користуються мільйони, у такій роботі досі залежить від того, чи тримає одна компанія на ній кількох людей, — а швидкість, на яку ви плануєте, має бути виміряною, а не взятою з дорожньої карти.

Де він вироджується

На Python поблажливо писати й безжально вгадувати. Майже кожна продакшн-проблема на цій сторінці — це пропущений діагноз, коли рядок першої таблиці сприйняли як інший, або перевірка, яку могла зробити машина, але її не попросили:

  • Потоки, додані, щоб пришвидшити обчислення на Python, — блокування гарантує, що це не допоможе (рядки 5 і 10).
  • Блокуючий виклик усередині асинхронного обробника зупиняє цикл для всіх інших запитів (рядок 4).
  • Фонові задачі без збереженого посилання, що можуть зникнути без жодної помилки.
  • Поелементні цикли по масивах там, де один виклик бібліотеки зробив би те саме скомпільованим кодом.
  • Спільний між потоками стан, захищений лише вірою в те, що його захищає GIL.
  • Підказки типів, написані й ніколи не перевірені, гірші за їх відсутність, бо їм вірять.
  • Залежності без файлу блокування або приватний індекс, доданий поруч із PyPI через --extra-index-url.
  • pickle.load чи torch.load на файлі, створеному кимось іншим.
  • Кількість воркерів, задана за звичкою, а не за виміряною пам’яттю, і тихо втрачений copy-on-write.
  • Версія за межею останньої колонки таблиці версій — з листопада 2026 року все старше за 3.11.

Чесна межа — швидкість інтерпретатора на коді, написаному на самому Python. Для роботи, чий гарячий цикл не можна віддати бібліотеці, — власна симуляція, парсер, алгоритм на кожен запит, — Python у десятки разів повільніший за компільовану мову, і ні потоки, ні asyncio цього не змінюють. Збірка без GIL дає такому коду більше ядер, а не швидкість на кожному. Python виграє там, де повільна частина — очікування, або де хтось уже написав гарячий цикл на C, C++ чи Rust; для решти чесна відповідь — виміряти й перенести гарячий цикл, а не весь сервіс.

Практична перевірка займає п’ять хвилин. Запустіть python --version у продакшн-образі й знайдіть рядок у таблиці версій. Пошукайте закомічений файл блокування і --extra-index-url у збірці. Запустіть тести один раз із PYTHONASYNCIODEBUG=1 і прочитайте, що він залогує. І звірте кількість воркерів сервера з пам’яттю, яку кожен воркер справді використовує, а не з кількістю ядер.

Коли це застосовувати

Застосовуйте, коли

  • Робота з даними, аналітика й машинне навчання, де в екосистеми немає серйозного конкурента.
  • API та внутрішні сервіси, чий час іде на очікування, — FastAPI з async пасує цій формі точно.
  • Продукти, яким швидко потрібні адмінка, акаунти й модель даних, — саме цим і є Django.
  • Автоматизація, скриптинг і склеювання систем, де читабельність важить більше за пропускну здатність.

Уникайте, коли

  • Обчислення на чистому Python, що мають зайняти всі ядра одного процесу, — якщо не підходять збірка без GIL і всі її розширення.
  • Критичні за затримкою шляхи в мікросекундах, де накладні витрати інтерпретатора — головна ціна.
  • Великі кодові бази без перевірки типів у збірці, де відсутність компілятора відчувається щорелізу.
  • Завантаження файлів моделей чи даних із ненадійних джерел у форматі, що може виконувати код.

Джерела й метод

На чому стоїть ця стаття

  • 23 джерела
  • 2 задокументовані збої
  • Перевірено 13 жовтня 2026 р.

Практики й походження термінів

очікування чи обчислення: потоки, GIL, asyncio, процеси й версії

Дослідження з Claude. Пошук і звірку першоджерел зроблено з Claude (Anthropic). Відбір, текст і перевірку фактів — редакція Anatomy of IT Product.

Було корисно?

Поділіться з тим, хто працює над тією ж задачею.