Python: SWIG против ctypes - PullRequest
       38

Python: SWIG против ctypes

53 голосов
/ 26 сентября 2008

В Python при каких обстоятельствах SWIG является лучшим выбором, чем ctypes для вызова точек входа в общих библиотеках? Предположим, у вас еще нет файлов интерфейса SWIG.

Каковы показатели производительности двух?

Ответы [ 10 ]

89 голосов
/ 04 февраля 2011

У меня богатый опыт использования swig. SWIG утверждает, что это быстрое решение для упаковки вещей. Но в реальной жизни ...


Минусы:

SWIG разработан, чтобы быть общим, для всех и для 20+ языков. Как правило, это приводит к недостаткам:
- требуется настройка (шаблоны SWIG .i), иногда это сложно,
- отсутствие обработки некоторых особых случаев (см. свойства python далее),
- недостаточная производительность для некоторых языков.

Минусы Python:

1) Несоответствие стиля кода . C ++ и python имеют очень разные стили кода (это очевидно, конечно), возможности быстрого превращения целевого кода в Pythonish очень ограничены. В качестве примера, это то, что нужно создавать свойства из методов получения и установки. Смотрите этот вопрос & 1018 *

2) Отсутствие широкого сообщества . У SWIG есть хорошая документация. Но если кто-то поймал то, чего нет в документации, информации вообще нет. Ни блоги, ни поиск в Google не помогают. Поэтому в таких случаях приходится копать сгенерированный SWIG-код ... Это ужасно, я бы сказал ...

Плюсы:

  • В простых случаях это действительно быстро, легко и просто

  • Если вы создали файлы интерфейса swig один раз, вы можете перенести этот код C ++ на ЛЮБОЙ из 20+ языков (!!!).

  • Одна большая проблема SWIG - это производительность. Начиная с версии 2.04 SWIG включает флаг «-builtin», который делает SWIG даже быстрее, чем другие автоматизированные способы упаковки. По крайней мере некоторые тесты показывают это.


Когда ИСПОЛЬЗОВАТЬ SWIG?

Итак, я пришел к выводу о двух случаях, когда можно использовать глоток:

2) Если нужно обернуть код C ++ для нескольких языков . Или, если потенциально может быть время, когда нужно распространять код на несколько языков. Использование SWIG надежно в этом случае.

1) Если нужно быстро обернуть всего несколько функций из некоторой библиотеки C ++ для конечного использования.


Живой опыт

Обновление :
Прошло полтора года, как мы конвертировали нашу библиотеку с помощью SWIG.

Сначала мы сделали версию на Python. Было несколько моментов, когда у нас были проблемы с SWIG - это правда. Но сейчас мы расширили нашу библиотеку до Java и .NET. Таким образом, у нас есть 3 языка с 1 SWIG. И я мог бы сказать, что SWIG качает с точки зрения экономии МНОГО времени.

Обновление 2 :
Уже два года мы используем SWIG для этой библиотеки. SWIG интегрирован в нашу систему сборки. Недавно у нас было серьезное изменение API библиотеки C ++. SWIG работал отлично. Единственное, что нам нужно было сделать, это добавить несколько% rename к файлам .i, чтобы наш CppCamelStyleFunctions() теперь looks_more_pythonish в python. Сначала меня беспокоили некоторые проблемы, которые могли возникнуть, но ничего не пошло не так. Это было прекрасно. Всего несколько правок и все распространено на 3 языках. Теперь я уверен, что это было хорошим решением использовать SWIG в нашем случае.

Обновление 3 :
Уже более 3 лет мы используем SWIG для нашей библиотеки. Основные изменения : часть Python полностью переписана на чистом Python. Причина в том, что Python сейчас используется для большинства приложений нашей библиотеки. Даже если версия на чистом Python работает медленнее, чем упаковка C ++, пользователям удобнее работать с чистым Python, не борясь с нативными библиотеками.

SWIG все еще используется для версий .NET и Java.

Главный вопрос здесь: «Будем ли мы использовать SWIG для Python, если мы начнем проект с самого начала?». Мы будем! SWIG позволил нам быстро распространять наш продукт на многих языках. Это работало в течение определенного периода времени, что дало нам возможность лучше понять требования наших пользователей.

62 голосов
/ 26 сентября 2008

SWIG генерирует (довольно некрасиво) код C или C ++. Он прост в использовании для простых функций (вещи, которые могут быть переведены напрямую) и достаточно прост в использовании для более сложных функций (таких как функции с выходными параметрами, которые требуют дополнительного шага перевода для представления в Python.) Для более мощного взаимодействия вы часто нужно написать биты C как часть файла интерфейса. Для всего, кроме простого использования, вам нужно знать о CPython и о том, как он представляет объекты - не сложно, но что-то нужно иметь в виду.

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

Вполне вероятно, что в чистом исполнении SWIG быстрее, чем ctypes - потому что управление реальной работой выполняется на C во время компиляции, а не в Python во время выполнения. Однако, если вы не подключите много разных функций Си, но каждую из них только несколько раз, маловероятно, что издержки будут действительно заметны.

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

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

13 голосов
/ 26 сентября 2008

CTypes - это очень круто и намного проще, чем SWIG, но у него есть недостаток, заключающийся в том, что плохо или злонамеренно написанный код Python может фактически вызвать сбой процесса Python. Вы также должны рассмотреть boost python. ИМХО, это на самом деле проще, чем глоток, давая вам больше контроля над финальным интерфейсом Python. Если вы все равно используете C ++, вы также не добавляете в свой микс другие языки.

10 голосов
/ 21 января 2009

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

Проблема в том, что большая часть вашего стека скрыта магией ctypes / ffi, и нет простого способа определить, как вы попали в конкретную точку и почему значения параметров такие, какие они есть.

8 голосов
/ 26 сентября 2008

Вы также можете использовать Pyrex , который может служить связующим звеном между кодом Python высокого уровня и кодом C низкого уровня. lxml написано, например, на Pyrex.

7 голосов
/ 26 сентября 2008

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

Ctypes тоже хорош, но, как говорили другие, он не делает C ++.

Насколько велика библиотека, которую вы пытаетесь обернуть? Как быстро меняется кодовая база? Любые другие проблемы обслуживания? Все это, вероятно, повлияет на выбор лучшего способа написания привязок Python.

6 голосов
/ 26 сентября 2008

ctypes великолепен, но не обрабатывает классы C ++. Я также обнаружил, что ctypes примерно на 10% медленнее, чем прямая привязка C, но это будет сильно зависеть от того, что вы называете.

Если вы собираетесь использовать ctypes, обязательно посмотрите проекты Pyglet и Pyopengl, в которых есть массивные примеры привязок ctype.

5 голосов
/ 04 августа 2011

Просто хотел добавить еще несколько соображений, которые я еще не упоминал. [РЕДАКТИРОВАТЬ: Упс, не видел ответ Майка Стедера]

Если вы хотите попробовать использовать реализацию, отличную от Cpython (например, PyPy, IronPython или Jython), тогда ctypes - это единственный путь. PyPy не позволяет писать C-расширения, поэтому исключаются pyrex / cython и Boost.python. По той же причине ctypes - единственный механизм, который будет работать для IronPython и (в конце концов, когда они все это заработают) jython.

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

3 голосов
/ 25 февраля 2011

Следует иметь в виду, что SWIG нацелен только на реализацию CPython. Поскольку ctypes также поддерживается реализациями PyPy и IronPython, возможно, стоит написать ваши модули с ctypes для совместимости с более широкой экосистемой Python.

0 голосов
/ 28 мая 2013

Я обнаружил, что SWIG немного раздут в своем подходе (в общем, не только в Python) и его трудно реализовать без необходимости пересекать больной вопрос написания кода Python с явным мышлением, чтобы быть дружественным к SWIG, а не написание чистого, хорошо написанного кода Python. ИМХО, это гораздо более простой процесс - писать привязки C к C ++ (если используется C ++), а затем использовать ctypes для взаимодействия с любым уровнем C.

Если библиотека, к которой вы подключаетесь, имеет интерфейс C как часть библиотеки, еще одним преимуществом ctypes является то, что вам не нужно компилировать отдельную библиотеку привязки Python для доступа к сторонним библиотекам. Это особенно удобно при разработке решения на чистом python, которое позволяет избежать проблем кросс-платформенной компиляции (для сторонних библиотек, предлагаемых на разнородных платформах). Необходимость встраивания скомпилированного кода в пакет, который вы хотите развернуть на чем-то вроде PyPi, кроссплатформенным дружественным способом - это боль; Одно из моих самых раздражающих замечаний о пакетах Python, использующих SWIG или явный код C, - это их общая кросс-платформенность. Поэтому подумайте об этом, если вы работаете с кроссплатформенными доступными сторонними библиотеками и разрабатываете решение на основе Python вокруг них.

В качестве реального примера рассмотрим PyGTK. Это (я считаю) использует SWIG для генерации C-кода для взаимодействия с C-вызовами GTK. Я использовал это в течение кратчайшего времени только для того, чтобы найти реальную боль в настройке и использовании, со странными странными ошибками, если вы не сделали все в правильном порядке при настройке и просто в целом. Это был такой разочаровывающий опыт, и когда я посмотрел на определения взаимодействия, предоставленные GTK в сети, я понял, что это будет простое упражнение - написать переводчик этого интерфейса в интерфейс Python ctypes. Родился проект под названием PyGGI, и в ОДИН день я смог переписать PyGTK, чтобы он стал гораздо более функциональным и полезным продуктом, который точно соответствует C-объектно-ориентированным интерфейсам GTK. И это не требует компиляции C-кода, что делает его кросс-платформенным. (Я был на самом деле после взаимодействия с webkitgtk, который не так кроссплатформенный). Я также могу легко развернуть PyGGI на любой платформе, поддерживающей GTK.

...