
GIL в Python: почему threading не ускоряет вычисления
Вы распараллелили расчёт на четыре потока, а он стал работать не быстрее, а иногда медленнее. Разбираем, как GIL в CPython решает, кто исполняет байт-код, и когда потоки реально помогают.

Вы распараллелили расчёт на четыре потока, а он стал работать не быстрее, а иногда медленнее. Разбираем, как GIL в CPython решает, кто исполняет байт-код, и когда потоки реально помогают.

Скрипт с requests опрашивает 200 URL за 90 секунд, переписанный на aiohttp — за 4. А иногда наоборот: asyncio добавляет накладных расходов и не даёт ничего. Разбираем, где проходит граница.

Корутина — не поток и не магия. Разбираем, во что превращается async def, как event loop дёргает ваши функции через send() и почему один блокирующий вызов вешает весь сервис.

Вы умеете писать синхронный Python, но asyncio ломает привычки: функции с async нельзя вызвать напрямую, а один блокирующий вызов вешает весь цикл. Разбираем, где очевидные приёмы дают сбой.

Три структуры из модуля collections закрывают задачи, где обычный dict и list заставляют писать лишний код и теряют в скорости. Разбираем, что каждая даёт и чем за это платишь.

Группировка, скользящее окно, разбивка на пачки и декартово произведение — задачи, которые обычно решают вложенными циклами, укладываются в один вызов из itertools. Разбираем рабочие приёмы для Python 3.12.

Три инструмента из functools экономят строки кода, но каждый бьёт по рукам в неожиданном месте: lru_cache течёт памятью, partial ломает интроспекцию, wraps молча теряет часть метаданных. Разбираем на конкретных задачах.

Разбираем, как for на самом деле обходит объекты, чем итератор отличается от итерируемого и почему одноразовый итератор ломается при повторном проходе.

Разбираем, какие dunder-методы делают ваш класс похожим на список: индексация, срезы, len, итерация и распаковка. Что реализовать, чтобы объект вёл себя предсказуемо, и где это ломается.

Один вызов reflect.ValueOf превращает статически типизированный Go в интерпретатор рантайма. Разбираем, что происходит внутри, почему рефлексия аллоцирует и когда её цена оправдана.

append на срезе-подрезке молча портит соседние данные, а один долгоживущий срез держит в памяти мегабайтный буфер. Разбираем, как это устроено внутри и что искать на ревью.

Как объявить и правильно инициализировать static-поля и методы, где их определять и что изменилось с C++17. Разбор на рабочих примерах с проверкой каждого шага.