Вызвать C++ из Python и получить медленнее: как interop-overhead обнуляет выигрыш от нативного кода

public

Автор: Александр Боргардт (duckstax) · Evrone Development


У питонистов есть простое правило: хочешь сделать быстро — пиши нативный код. Это действительно так, когда нативный код пишут опытные C/C++-разработчики. Но те, кто только начинает погружаться в эту область, часто обнаруживают что стало не быстрее, а медленнее. Боргардт объясняет почему — и как это исправить.

Реальный кейс: ML pipeline с видеопотоком, задача — поиск объектов в кадре в реальном времени. На каком-то этапе всё начало тормозить. Расследование привело не к проблеме в алгоритме, а к проблеме на границе Python–C++: неявные накладные расходы при вызове нативного кода из Python.

Кому смотреть: Python-разработчикам, которые пишут или планируют писать C++-расширения — и хотят понять, почему «просто вынести в C++» не всегда означает «стало быстрее».

Из этого можно взять в работу: если пишете C++-модуль для Python и работаете с большими массивами данных — изучите Buffer Protocol (PEP 3118). Это стандартный механизм zero-copy передачи данных между Python и нативным кодом, который поддерживают numpy, bytearray, bytes.


Таймкоды: вступление (0:16), описание проекта (1:31), когда всё начало тормозить (6:00), где начинается проблема (9:25), interop (11:24), как всё починить (13:27), Buffer Protocol (14:40), как переписать код (16:43), большие объекты (17:35), результат (19:02), правила написания модулей на C++ (19:32), выводы (22:45).

Ключевое понятие доклада — interop overhead: каждый вызов из Python в C++ несёт накладные расходы на преобразование типов, управление памятью и работу с GIL. Когда нативная функция вызывается в цикле с маленькими объектами — overhead может превышать само вычисление.

Buffer Protocol позволяет C++-модулю принимать данные напрямую из памяти Python-объекта без копирования. Если передаёте большой массив в нативный код — разница между «с Buffer Protocol» и «без» может быть принципиальной.