Сведения о вопросе

Life

13:08, 9th August, 2020

Теги

Прототипирование с помощью кода Python перед компиляцией

Просмотров: 693   Ответов: 7

Я уже некоторое время обдумываю написание библиотеки peak fitting. Я знаю Python довольно хорошо и планирую реализовать все в Python для начала, но предполагаю, что мне, возможно, придется повторно реализовать некоторые основные подпрограммы на скомпилированном языке в конечном итоге.

IIRC, один из первоначальных ремитов Python был как язык прототипирования, однако Python довольно либеральен в разрешении функций, функторов, объектов для передачи в функции и методы, тогда как я подозреваю, что то же самое не верно для say C или Fortran.

Что я должен знать о проектировании функций / классов, которые я предполагаю, должны будут взаимодействовать с компилируемым языком? И сколько из этих потенциальных проблем решается такими библиотеками, как cTypes, bgen , SWIG , Boost.Python, Cython или Python SIP ?

Для этого конкретного случая использования (подходящая библиотека) я предполагаю, что пользователи могут определять математические функции (Guassian, Lorentzian и т. д.) как функции Python, которые затем могут быть переданы интерпретируемой библиотекой скомпилированного кода. Передача и возврат массивов также имеет важное значение.



  Сведения об ответе

LAST

11:34, 14th August, 2020

Наконец, вопрос, на который я действительно могу дать ценный ответ :).

Я исследовал f2py, boost.python, swig, cython и pyrex для своей работы (PhD в оптических методах измерения). Я использовал swig экстенсивно, boost.python немного и Пирекс и цитон много. Я также использовал ctypes. Это мой срыв:

Отказ от ответственности: это мой личный опыт. Я не участвую ни в одном из этих проектов.

swig: не очень хорошо играет с c++. Это должно быть, но проблемы с искажением имен на этапе связывания были для меня главной головной болью на linux & Mac OS X. Если у вас есть код C и вы хотите, чтобы он был сопряжен с python, это хорошее решение. Я завернул GTS для своих нужд и должен был написать в основном общую библиотеку C, к которой я мог бы подключиться. Я бы не рекомендовал этого делать.

Ctypes: я написал оболочку libdc1394 (IEEE Camera library), используя ctypes, и это был очень прямой опыт. Вы можете найти код на https://launchpad.net/pydc1394 . Для преобразования заголовков в код python требуется много работы, но тогда все работает надежно. Это хороший способ, если вы хотите взаимодействовать с внешней библиотекой. Ctypes также находится в stdlib python, так что каждый может сразу же использовать ваш код. Это также хороший способ быстро поиграть с новым lib в python. Я могу рекомендовать его для интерфейса с внешними либами.

Boost.Python: очень приятно. Если у вас уже есть собственный код C++, который вы хотите использовать в python, перейдите к этому. Таким образом, очень легко перевести структуры классов c++ в структуры классов python. Я рекомендую его, если у вас есть код c++, который вам нужен в python.

Pyrex/Cython: используйте Цитон, а не Пирекс. Период. Cython является более продвинутым и более приятным в использовании. В настоящее время я делаю с cython все, что раньше делал с SWIG или Ctypes. Это также лучший способ, если у вас есть код python, который работает слишком медленно. Процесс абсолютно фантастический: вы конвертируете свои модули python в модули cython, строите их и продолжаете профилировать и оптимизировать, как это было до сих пор python (без необходимости смены инструментов). Затем вы можете применить как можно больше (или как можно меньше) кода C, смешанного с вашим кодом python. Это намного быстрее, чем переписывать целые части вашего приложения в C; вы переписываете только внутренний цикл.

Тайминги: ctypes имеет самые высокие накладные расходы вызова (~700ns), затем следует boost.python (322ns), а затем непосредственно swig (290ns). У Cython самые низкие накладные расходы на звонки (124n) и лучшая обратная связь, когда он тратит время на (cProfile поддержка!). Числа взяты из моего ящика, вызывающего тривиальную функцию, которая возвращает целое число из интерактивного shell; поэтому накладные расходы на импорт модуля не синхронизированы, а только накладные расходы на вызов функции. Поэтому проще и продуктивнее всего быстро получить код python с помощью профилирования и использования cython.

Резюме: для вашей проблемы используйте Cython ;). Я надеюсь, что это краткое изложение будет полезно для некоторых людей. Я с радостью отвечу на любой оставшийся вопрос.


Edit: я забыл упомянуть: для числовых целей (то есть для подключения к NumPy) используется Cython; у них есть поддержка для него (потому что они в основном разрабатывают cython для этой цели). Так что это должно быть еще одно +1 для вашего решения.


  Сведения об ответе

JUST___

00:21, 22nd August, 2020

Я не использовал SWIG или SIP, но я нахожу написание Python обертки с boost.python очень мощным и относительно простым в использовании.

Я не совсем понимаю, каковы ваши требования для передачи типов между C/C++ и python, но вы можете легко сделать это, либо предоставив тип C++ python, либо используя универсальный аргумент boost::python::object для вашего C++ API. Вы также можете зарегистрировать конвертеры для автоматического преобразования типов python в типы C++ и наоборот.

Если вы планируете использовать boost.python, этот учебник -хорошее место для начала.

Я реализовал нечто в некотором роде похожее на то, что вам нужно. У меня есть функция C++, которая принимает функцию python и изображение в качестве аргументов и применяет функцию python к каждому пикселю изображения.

Image* unary(boost::python::object op, Image& im)
{
    Image* out = new Image(im.width(), im.height(), im.channels());
    for(unsigned int i=0; i<im.size(); i++)
    {
        (*out)[i] == extract<float>(op(im[i]));
    }
    return out;
}

В этом случае Image-это объект C++, открытый для python (изображение с плавающими пикселями), а op-это определенная функция python (или действительно любой объект python с атрибутом __call__). Затем вы можете использовать эту функцию следующим образом (предполагая, что унарный находится в вызываемом образе, который также содержит изображение и функцию загрузки):

import image
im = image.load('somefile.tiff')
double_im = image.unary(lambda x: 2.0*x, im)

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


  Сведения об ответе

VCe znayu

16:08, 2nd August, 2020

Лучший способ спланировать возможный переход к компилированному коду-написать чувствительные к производительности части в виде модуля простых функций в функциональном стиле (без состояния и без побочных эффектов), которые принимают и возвращают основные типы данных.

Это обеспечит сопоставление one-to-one из вашего кода прототипа Python с конечным скомпилированным кодом, а также позволит вам легко использовать ctypes и избежать целой кучи головных болей.

Для пиковой подгонки вам почти наверняка придется использовать массивы, что немного усложнит ситуацию, но все еще очень выполнимо с ctypes.

Если вы действительно хотите использовать более сложные структуры данных или изменить переданные аргументы, стандартный интерфейс SWIG или Python с расширением C позволит вам делать то, что вы хотите, но с некоторым количеством хлопот.

Для того, что вы делаете , вы также можете проверить NumPy, который может выполнить часть работы, которую вы хотели бы продвинуть до C, а также предложить некоторую дополнительную помощь в перемещении данных между Python и C .


  Сведения об ответе

lool

09:06, 29th August, 2020

f2py (часть numpy)является более простой альтернативой SWIG и boost.python для обертывания кода с номером C/Fortran.


  Сведения об ответе

qwerty101

05:03, 12th August, 2020

По моему опыту, есть два простых способа вызвать код C из кода Python. Есть и другие подходы, все они более раздражающие и/или многословные.

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

Второй самый простой способ-написать модуль Python в C и затем вызвать функции в этом модуле. Вы можете передать все, что хотите, в эти функции C, не перепрыгивая через какие-либо обручи. И это легко вызвать Python функции или методы из этих C функций, как описано здесь: https://docs.python.org/extending/extending.html#calling-python-functions-from-c

У меня нет достаточного опыта работы с SWIG, чтобы предложить разумный комментарий. И хотя можно делать такие вещи, как передавать пользовательские объекты Python в функции C через ctypes или определять новые классы Python в C, эти вещи раздражают и многословны, и я рекомендую использовать один из двух подходов, описанных выше.


  Сведения об ответе

park

07:08, 6th August, 2020

В дополнение к перечисленным выше инструментам я могу рекомендовать использовать Pyrex (для создания модулей расширения Python) или Psyco (как компилятор JIT для Python).


  Сведения об ответе

PROGA

00:51, 7th August, 2020

Python довольно либерально позволяет передавать функции, функторы, объекты в функции и методы, в то время как я подозреваю, что то же самое не верно для say C или Fortran.

В C вы не можете передать функцию в качестве аргумента функции, но вы можете передать указатель функции, который является такой же хорошей функцией.

Я не знаю, насколько это поможет, когда вы пытаетесь интегрировать код C и Python, но я просто хотел прояснить одно заблуждение.


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться