[Python-de] Extension

Stefan Behnel python-de at behnel.de
Mi Mär 28 08:40:09 CEST 2012


Bernd Nawothnig, 27.03.2012 20:29:
> On 2012-03-27, Stefan Behnel wrote:
>> Bernd Nawothnig, 27.03.2012 17:03:
>>> Ein Pythonprogramm ruft eine in C geschriebene Extension mit einem
>>> Parameter auf, der aus einer in ein numpy.array konvertierten
>>> Python-Liste von Objekten besteht. Das C-Programm nutzt dazu einen
>>> Zeiger auf dieses nun eng gepackte Array von Zeigern und wählt durch
>>> einen geeigneten Algorithmus aus dieser Objektmenge einige aus, die
>>> nun in eine Python-Liste von Python-Listen von Objekten gekapselt
>>> zurückgegeben werden. Freigegeben oder verändert wird keines der beim
>>> Aufruf der Extension übergebenen Objekte. Die Python-Ergebnisliste
>>> wird in C so konstruiert:
>>> ...
>>> PyObject *r = PyList_New(0);
>>> ...
>>> static PyObject *VLP_asPyList(VectorlistP *vl)
>>> {
>>>     PyObject *result = PyList_New(vl->length);
>>>     int i;
>>>
>>>     for (i=0; i<vl->length; i++)
>>>       PyList_SetItem(result, i, Py_BuildValue("O", vl->list[i]->anomaly));
>>> //                                                 ^^^^^^^^^^^^^^^^^^^^
>>> //                         Zeiger auf eins der ursprünglichen Objekte
>>>     return result;
>>> }
>>> ...
>>> PyList_Append(r, VLP_asPyList(&bestResult));
>>
>> Hier war ein "extend()" gemeint, oder?
> 
> Nein, ein PyList_Append, also entsprechend einem python <list>.append().
> 
>>> return r;
>>
>> Zum Vergleich der (mangels umgebendem Code und Daten natürlich ungetestete)
>> äquivalente Code in Cython:
>>
>>   return [ item.anomaly for item in bestResult.list[:bestResult.length] ]
>>
>> Finde ich hübscher und übersichtlicher.
> 
> Im reinen C-Teil verwende ich ja absichtlich _nicht_ die
> Python-Datenstrukturen

Hatte ich auch so verstanden. Der Code oben (deiner und meiner) dient nur
der Konvertierung des Ergebnisses von C nach Python.

Der Code, den Cython generiert, hat nur minimal höheren Aufwand als dein
handgeschriebener - er erzeugt die ursprüngliche Liste nämlich momentan
nicht mit der finalen Länge. Und das auch nur deshalb, weil ich immer noch
keine Zeit gefunden habe, die bekannte Länge der Ergebnisliste aus dem
Iterator durchzuschleifen. Sprich: mit ein bisschen zusätzlichem Aufwand
würde Cython sogar identischen Code generieren, ohne deinen ganzen C
Eiertanz oben.

Allerdings würde es mich überraschen, wenn der Geschwindigkeitsunterschied
jetzt schon sehr auffällig wäre. Der eher meistens vernachlässigbar, weil
die Konvertierung der Listeneinträge normalerweise deutlich stärker zu
Buche schlägt als die Vergößerung der Liste, die meistens ohnehin von der
Speicherverwaltung aufgefangen wird.


>, weil ich eben schneller werden will (was auch
> weit über alle Erwartungen geklappt hat ;-). Gerade die dauernden
> appends, bzw. auch Listcomprehensions, wie Du sie erwähntest (ich
> weiß, die sind sehr elegant und ich verwende die auch sehr gerne),
> holen sich jedes Mal Speicher vom Heap, der praktisch dann gleich
> wieder freigegeben werden kann

Äh, bitte wie? Warum sollten sie das denn tun?


> während der mir sehr wohl bekannte
> wirkliche Speicherverbrauch dieses Algorithmus _sehr_ überschaubar
> ist. Entsprechend dramatisch war dann auch der Speedup (mehr als
> Faktor 1000).

Aber nur gegenüber CPython, richtig?


> static PyObject *VLP_asPyList(VectorlistP *vl)
> 
> macht aus meiner C-Variante ganz zum Schluss erst(!) Python, weil ich
> das Resultat ja schließlich und letztendlich in Python haben möchte.

Ja, das ist das übliche Vorgehen. Deshalb haben wir uns mit unseren beiden
Implementierungen ja auch auf den Teil beschränkt.


> Aber viel mehr würde mich interessieren, ob PyList_SetItem und
> PyList_Append automatisch den Referenzzähler der eingefügten, bzw.
> zugewiesenen Objekte erhöhen.

Schau in die Doku (wie Dietmar es für dich getan hat). Unnötig zu sagen,
dass Cython dir diese Details abnimmt.

Stefan


Mehr Informationen über die Mailingliste python-de