Domanda

In Python, in quali circostanze SWIG è una scelta migliore rispetto ai ctypes per chiamare i punti di ingresso nelle librerie condivise? Supponiamo che tu non abbia già i file di interfaccia SWIG.

Quali sono le metriche delle prestazioni dei due?

È stato utile?

Soluzione

SWIG genera (piuttosto brutto) codice C o C ++. È semplice da usare per funzioni semplici (cose che possono essere tradotte direttamente) e ragionevolmente facili da usare per funzioni più complesse (come funzioni con parametri di output che richiedono un passaggio di traduzione aggiuntivo per rappresentare in Python). Per interfacce più potenti spesso è necessario scrivere bit di C come parte del file di interfaccia. Per tutto tranne che per un semplice utilizzo, devi conoscere CPython e come rappresenta gli oggetti, non difficile, ma qualcosa da tenere a mente.

ctypes ti consente di accedere direttamente alle funzioni C, alle strutture e ad altri dati e di caricare librerie condivise arbitrarie. Non è necessario scrivere C per questo, ma è necessario capire come funziona C. È, si potrebbe argomentare, il rovescio della medaglia di SWIG: non genera codice e non richiede un compilatore in fase di esecuzione, ma per qualsiasi cosa tranne che per un semplice utilizzo richiede di capire come cose come i tipi di dati C, il cast, gestione della memoria e lavori di allineamento. È inoltre necessario tradurre manualmente o automaticamente strutture C, sindacati e matrici nella struttura dati equivalente di ctypes, incluso il giusto layout di memoria.

È probabile che, in pura esecuzione, SWIG sia più veloce dei tipi - perché la gestione attorno al lavoro effettivo viene eseguita in C a compiletime anziché in Python in fase di esecuzione. Tuttavia, a meno che non si interfacciano molte funzioni C diverse ma ognuna solo poche volte, è improbabile che l'overhead sia davvero evidente.

In fase di sviluppo, ctypes ha un costo di avvio molto più basso: non è necessario conoscere i file di interfaccia, non è necessario generare file .c e compilarli, non è necessario effettuare il checkout e il silenzio avvertenze. Puoi semplicemente saltare e iniziare a utilizzare una singola funzione C con il minimo sforzo, quindi espanderlo ad altro. E puoi testare e provare le cose direttamente nell'interprete Python. Il wrapping di un sacco di codice è un po 'noioso, anche se ci sono tentativi per renderlo più semplice (come ctypes-configure.)

SWIG, d'altra parte, può essere utilizzato per generare wrapper per più lingue (salvo i dettagli specifici della lingua che devono essere compilati, come il codice C personalizzato che ho menzionato sopra.) Quando si racchiudono un sacco di codice che SWIG può gestire con un piccolo aiuto, la generazione del codice può anche essere molto più semplice da configurare rispetto agli equivalenti di tipo.

Altri suggerimenti

Ho una ricca esperienza nell'uso di swig. SWIG afferma che si tratta di una soluzione rapida per il confezionamento di oggetti. Ma nella vita reale ...


Contro:

SWIG è sviluppato per essere generale, per tutti e per oltre 20 lingue. In generale, porta a svantaggi:
- necessita di configurazione (modelli SWIG .i), a volte è complicato,
- mancanza di trattamento di alcuni casi speciali (vedere più avanti le proprietà del pitone),
- mancanza di prestazioni per alcune lingue.

Contro di Python:

1) Incoerenza dello stile del codice . C ++ e python hanno stili di codice molto diversi (questo è ovvio, certamente), le possibilità di una sorsata di rendere il codice target più Pythonish sono molto limitate. Ad esempio, è fondamentale creare proprietà da getter e setter. Vedi questo q & amp; a

2) Mancanza di un'ampia comunità . SWIG ha una buona documentazione. Ma se si cattura qualcosa che non è nella documentazione, non ci sono informazioni. Nessun blog o googling aiuta. Quindi in questi casi è necessario scavare pesantemente il codice generato da SWIG ... È terribile, potrei dire ...

Pro:

  • In casi semplici, è davvero rapido, facile e diretto

  • Se hai prodotto una volta i file dell'interfaccia di swig, puoi racchiudere questo codice C ++ in QUALSIASI delle altre 20 lingue (!!!).

  • Una grande preoccupazione per SWIG è una performance. Dalla versione 2.04 SWIG include il flag '-builtin' che rende SWIG ancora più veloce di altri modi automatici di avvolgimento. Almeno alcuni benchmark lo mostrano.


Quando USARE SWIG?

Quindi ho concluso per me due casi in cui il sorso è buono da usare:

2) Se è necessario racchiudere il codice C ++ per diverse lingue . O se potenzialmente ci potrebbe essere un momento in cui è necessario distribuire il codice per più lingue. L'uso di SWIG è affidabile in questo caso.

1) Se è necessario rapidamente avvolgere solo alcune funzioni da alcune librerie C ++ per l'uso finale.


Esperienza dal vivo

Aggiorna :
È passato un anno e mezzo mentre facevamo una conversione della nostra biblioteca usando SWIG.

Innanzitutto, abbiamo realizzato una versione di Python. Ci sono stati diversi momenti in cui abbiamo riscontrato problemi con SWIG - è vero. Ma in questo momento abbiamo ampliato la nostra libreria a Java e .NET. Quindi abbiamo 3 lingue con 1 SWIG. E potrei dire che SWIG spacca in termini di risparmio di MOLTO tempo.

Aggiornamento 2 :
Sono due anni che utilizziamo SWIG per questa libreria. SWIG è integrato nel nostro sistema di generazione. Recentemente abbiamo avuto importanti cambiamenti API nella libreria C ++. SWIG ha funzionato perfettamente. L'unica cosa che dovevamo fare è aggiungere diversi% rinominare ai file .i, quindi il nostro CppCamelStyleFunctions () ora looks_more_pythonish in python. All'inizio ero preoccupato per alcuni problemi che potevano sorgere, ma nulla è andato storto. E 'stato stupefacente. Solo diverse modifiche e tutto distribuito in 3 lingue. Ora sono sicuro che sia stata una buona soluzione usare SWIG nel nostro caso.

Aggiornamento 3 :
Sono 3+ anni che utilizziamo SWIG per la nostra biblioteca. Cambiamenti importanti : la parte di Python è stata completamente riscritta in puro Python. Il motivo è che Python è ora utilizzato per la maggior parte delle applicazioni della nostra libreria. Anche se la versione Python pura funziona più lentamente del wrapping C ++, è più conveniente per gli utenti lavorare con Python puro, non alle prese con le librerie native.

SWIG è ancora usato per le versioni .NET e Java.

La domanda principale qui " Useremmo SWIG per Python se avessimo avviato il progetto dall'inizio? " ;. Noi vorremmo! SWIG ci ha permesso di distribuire rapidamente il nostro prodotto in molte lingue. Ha funzionato per un periodo di tempo che ci ha dato l'opportunità di comprendere meglio le esigenze dei nostri utenti.

CTypes è molto interessante e molto più semplice di SWIG, ma ha lo svantaggio che il codice Python scritto male o malevolutamente può effettivamente arrestare il processo Python. Dovresti anche prendere in considerazione boost python. IMHO è in realtà più semplice del swig mentre ti dà più controllo sull'interfaccia finale di Python. Se usi C ++ comunque, non aggiungi altre lingue al tuo mix.

Nella mia esperienza, i tipi hanno un grosso svantaggio: quando qualcosa va storto (e invariabilmente lo farà per qualsiasi interfaccia complessa), è un inferno da debug.

Il problema è che gran parte del tuo stack è oscurato dalla magia ctypes / ffi e non esiste un modo semplice per determinare come sei arrivato a un punto particolare e perché i valori dei parametri sono quelli che sono ..

Puoi anche usare Pyrex , che può agire come colla tra codice Python di alto livello e codice C di basso livello. lxml è scritto in Pyrex, per esempio.

Sarò contrarian e suggerirò che, se puoi, dovresti scrivere la tua libreria di estensioni usando API Python standard . È davvero ben integrato sia dal punto di vista C che Python ... se hai qualche esperienza con l'API Perl, la troverai una molto piacevole sorpresa.

Anche Ctypes è carino, ma come altri hanno già detto, non fa C ++.

Quanto è grande la libreria che stai cercando di avvolgere? Quanto velocemente cambia la base di codice? Altri problemi di manutenzione? Questi probabilmente influenzeranno probabilmente la scelta del modo migliore per scrivere i binding di Python.

ctypes è eccezionale, ma non gestisce le classi C ++. Ho anche scoperto che i ctypes sono circa il 10% più lenti di un'associazione C diretta, ma ciò dipenderà fortemente da ciò che stai chiamando.

Se hai intenzione di andare con i Ctype, dai un'occhiata ai progetti Pyglet e Pyopengl, che hanno enormi esempi di attacchi per Ctype.

Volevo solo aggiungere alcune considerazioni che non avevo ancora visto menzionate. [EDIT: Ooops, non ho visto la risposta di Mike Steder]

Se vuoi provare a usare un'implementazione non Cpython (come PyPy, IronPython o Jython), allora i ctypes sono l'unica strada da percorrere. PyPy non consente la scrittura di estensioni C, quindi esclude pyrex / cython e Boost.python. Per lo stesso motivo, ctypes è l'unico meccanismo che funzionerà per IronPython e (eventualmente, una volta che tutto funzionerà) jython.

Come è stato menzionato da qualcun altro, non è richiesta alcuna compilazione. Ciò significa che se esce una nuova versione di .dll o .so, puoi semplicemente rilasciarla e caricare quella nuova versione. Fintanto che nessuna delle interfacce è cambiata, si tratta di un calo nella sostituzione.

Qualcosa da tenere a mente è che SWIG prende di mira solo l'implementazione di CPython. Poiché ctypes è supportato anche dalle implementazioni di PyPy e IronPython, potrebbe valere la pena scrivere i moduli con ctypes per la compatibilità con l'ecosistema Python più ampio.

Ho scoperto che SWIG è un po 'gonfio nel suo approccio (in generale, non solo Python) e difficile da implementare senza dover attraversare il punto dolente della scrittura di codice Python con una mentalità esplicita per essere SWIG amichevole, piuttosto che scrivere codice Python ben scritto e pulito. È, IMHO, un processo molto più semplice per scrivere i collegamenti C in C ++ (se si utilizza C ++) e quindi usare i ctypes per interfacciarsi a qualsiasi livello C.

Se la libreria a cui ci si sta interfacciare ha un'interfaccia C come parte della libreria, un altro vantaggio di ctypes è che non è necessario compilare una libreria di associazione pitone separata per accedere a librerie di terze parti. Questo è particolarmente utile nel formulare una soluzione pure-python che evita problemi di compilazione multipiattaforma (per quelle librerie di terze parti offerte su piattaforme diverse). Dover incorporare il codice compilato in un pacchetto che desideri distribuire su qualcosa come PyPi in un modo compatibile con più piattaforme è una seccatura; uno dei miei punti più irritanti sui pacchetti Python che usano SWIG o il codice esplicito C sottostante è la loro generale indisponibilità multipiattaforma. Quindi considera questo se stai lavorando con librerie di terze parti disponibili multipiattaforma e stai sviluppando una soluzione Python attorno a loro.

Come esempio del mondo reale, considera PyGTK. Questo (credo) usa SWIG per generare il codice C per interfacciarsi con le chiamate C GTK. L'ho usato per il breve periodo solo per trovarlo un vero problema da configurare e utilizzare, con strani errori strani se non hai fatto le cose nell'ordine corretto al momento dell'installazione e in generale. È stata un'esperienza così frustrante, e quando ho guardato le definizioni di interazione fornite da GTK sul web mi sono reso conto che sarebbe stato un semplice esercizio scrivere un traduttore di quelle interfacce nell'interfaccia di tipo pitone. È nato un progetto chiamato PyGGI e in UN giorno sono stato in grado di riscrivere PyGTK per essere un prodotto molto più funzionale e utile che si abbina perfettamente alle interfacce orientate agli oggetti GTK C. E non richiedeva la compilazione di codice C che lo rendesse compatibile con la piattaforma. (In realtà ero dopo l'interfaccia con webkitgtk, che non è così multipiattaforma). Posso anche distribuire facilmente PyGGI su qualsiasi piattaforma che supporti GTK.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top