Как ускорить Python с помощью C ?
2026-03-10 02:39 Diff

Теги: python, с, компилятор, c api, cpython, компиляция, портируемость кода, reference management, cython, swig, binding, shared libraries, ctypes, cffi, pypy, .h, libffi

Безусловно, Python хорош всем. Но иногда всё же хочется немножко побыстрее. Сначала совершаются попытки изменить алгоритмический подход. Но если и этого не хватает, то дело серьёзное, пора засучивать рукава и расчехлять С-компилятор.

Кстати говоря, эта необходимость не всегда бывает вызвана проблемами с производительностью. Иногда просто нужно вызывать какой-нибудь C-функционал из Python, чтобы, например, протестировать его. Есть разные варианты скрещивания Python и С в зависимости от навыков и потребностей.

Рассмотрим три способа

  • Непосредственно писать на С, связываясь с Python через C API, который предоставляет CPython. Это путь для тех, кто неплохо владеет С и хочет иметь практически полный контроль над тем, что происходит. Но это возлагает на программиста ответственность за компиляцию, портируемость кода и даже за reference management объектов интерпретатора.
  • Писать код, который транслируется в C. Обычно в данном случае подразумевает использование Cython. Любой Python-код = уже валидный Cython-код! Cython сгенерит (особенно с помощью аннотаций, за написание которых уже отвечает программист) С-код, по возможности применив различные оптимизации и обеспечив портируемость. Минусы тут следуют из плюсов: опять нужно компилировать, нужно учить новый синтаксис и инструменты. Есть еще SWIG, но он скорее полезен для тех случаев, когда есть необходимость сделать много binding’ов к одному С-коду.
  • Писать код, который вызывает С-функции из разделяемых библиотек (shared libraries). Здесь многое зависит от того, насколько «развесистый» интерфейс необходимо вызывать. Для небольших вполне подходит ctypes – встроенного в CPython механизма. Проблема лишь в том, что описание вызываемых функций, передаваемых типов, кастинг и пр. – всё это крайне подвержено ошибкам. Да и читается это тяжело. Поэтому для сложных интерфейсов лучше подойдет cffi от создателей Pypy. Этой библиотеке не нужно всё объяснять, она сама многое выяснит, взглянув на .h-файл. Оба инструмента работают за счёт libffi, которая позволяет получить знание «как вызвать С-функцию», грубо говоря, объединив символы из разделяемой библиотеки и описание из .h-файла.

Есть вопрос? Напишите в комментариях!