8/24/2011

Extending Python with C/C++

Единственный весомый недостаток питона, с которым я столкнулся - его невысокая производительность. Всем известно, что узкое горло производительности в решениях на питоне во многом решается C/C++ расширениями. Эта статья о моих экспериментах в этой области. Для меня были очевидны три способа расширения функциональности Python на платформе win32:
  1. Создание модуля Python написанного на С/С++ (родной и мульти-платформенный подход)
  2. Импорт win32 функций из DLL для windows (удобный подход, можно вызывать как и стандартные API функции так и собственные)
  3. Взаимодействие со стандартными (или) самописными COM объектами
Итак, по порядку:

  • Инструменты для написания / сборки и их настройка
Ввиду того, что всё что я делал до сих пор касается платформы win32, вся информация о конфигурировании относится к Windows 7 x64 и Python 2.7. Для написания модуля расширения мне пришлось использовать обыкновенный текстовый редактор, командную строку Windows и MinGW (Minimalist GNU for Windows).
Начнем с установки и настройки MinGW. Загружаем MinGW с официального сайта переходим в раздел Downloads и загружаем последнюю версию MinGW (Automated MinGW Installer). Устанавливаем MinGW по-умолчанию в C:\MinGW\ и прописываем переменные окружения. Для указания переменных окружения открываем Controle panel -> System -> Advanced system settings в открывшемся окне (System properties) выбираем вкладку Advanced и нажимаем кнопку Environment Variables. Далее в открывшемся окне (Environment Variables) в таблице System variables выбираем переменную с именем Path, нажимаем Edit и прописываем в Variable value путь к компилятору "C:\MinGW\bin". На этом установка MinGW завершена.
  • Создание модуля Python написанного на С/С++ (родной и мульти-платформенный подход)
В обзорных целях нужно обратить внимание не то, что реализация стандартного CPython из коробки поддерживает создание модулей расширения на C/C++. И в документации об этом сказано и примеры доступны так же. Однако есть одно НО. На каждой из поддерживаемых платформ наверняка существует специфика подобной реализации. Так как мои изыскания лежат в поле обычной винды, опишу реализацию этих расширений именно для win32.
Итак, исходя из моих наблюдений, модуль для питон написанный на С - простая Dll стандартного формата windows, которая отвечает определенному контракту. Правда есть один нюанс (возможно это не есть общее правило, но пока я не знаю альтернатив), все собранные модули на С/С++ представляют собой DLL, но с форматом имени файла *.pyd и находятся тут: Python27\DLLs\  пока сообразил, убил кучу времени.
По сути создание такого модуля сводится к следующим шагам:
  1. Пишем на С/С++ тела DLL соблюдая контракт. По сути контракт этот гласит, что dll обязана экспортировать функцию (может быть не одна) initXXX, которая по сути призвана произвести все регистрации.
  2. Собираем её в DLL
  3. Копируем её в Python27\DLLs\  с расширением *.pyd
  4. Используем этот модуль так же, как и написанные на питоне (import mymodule)
Вот мой пример пошагово:
    • В отдельной папке (CPath) зоздаем исходник CPath.c следующего вида
#include "C:\Python27\include\Python.h"

static PyObject * CPath_findPath(PyObject *self, PyObject *args) 
{
//
    return NULL;
}

static PyMethodDef CPathMethods[] = {
    {"findPath", CPath_findPath, METH_VARARGS, "An error occured while path calculating"},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
initCPath(void)
{
    (void) Py_InitModule("CPath", CPathMethods);
}

int main(int argc, char *argv[]) {
    Py_SetProgramName(argv[0]);
    Py_Initialize();
    initCPath();
    return 0;
}

    • после этого собираем объектный файл
gcc -c CPath.c c:\Python27\libs\python27.lib 

Получаем: CPath.o 

    • Собираем саму библиотеку
gcc -shared CPath.o c:\Python27\libs\python27.lib -o CPath.pyd

Получаем: CPath.pyd 
    • Копируем CPath.pyd в Python27\DLLs\
    • Теперь имеем доступный из питона модуль CPath с единственным экспортом findPath()

import CPath

CPath.findPath("Params should be sent here")
  • Импорт win32 функций из DLL для windows (удобный подход, можно вызывать как и стандартные API функции так и собственные)
-текст-
  • Взаимодействие со стандартными (или) самописными COM объектами
-текст-

Ресурсы, которыми я пользовался для получения знаний:

Lessons in Python/C++ Interactions
Extending Python with C or C++
Python/C API Reference Manual

2 комментария:

  1. Где пример использования com объекта? Хоть бы привел пример интеракшина с MS EXCEL

    ОтветитьУдалить