Portable / schnelle Möglichkeit, einen Zeiger auf Numpy / Numpypy-Daten zu erhalten

8

Ich habe vor kurzem PyPy ausprobiert und war von dem Ansatz fasziniert. Ich habe viele C-Erweiterungen für Python, die alle PyArray_DATA() verwenden, um einen Zeiger auf die Datenabschnitte von numpy -Arrays zu erhalten. Unglücklicherweise scheint PyPy kein Äquivalent für ihre numpypy -Arrays in ihrem cpyext -Modul zu exportieren, also habe ich versucht, der Empfehlung auf ihrer Website zu folgen, um ctypes zu verwenden. Dies verschiebt die Aufgabe, den Zeiger auf die Python-Ebene zu erhalten.

Es gibt zwei Möglichkeiten:

%Vor%

Nur der zweite arbeitet mit PyPy, daher ist die Auswahl aus Kompatibilitätsgründen klar. Für CPython sind beide langsam und ein kompletter Flaschenhals für meine Anwendung! Gibt es eine schnelle und portable Möglichkeit, diesen Zeiger zu erhalten? Oder gibt es ein Äquivalent von PyArray_DATA() für PyPy (möglicherweise undokumentiert)?

    
Stefan 04.03.2013, 20:24
quelle

2 Antworten

4

Ich habe immer noch keine vollkommen zufriedenstellende Lösung gefunden, aber dennoch gibt es etwas, was man tun kann, um den Zeiger mit viel weniger Overhead in CPython zu erhalten. Erstens, der Grund, warum beide oben genannten Wege so langsam sind, ist, dass sowohl .ctypes als auch .__array_interface__ On-Demand-Attribute sind, die durch array_ctypes_get() und array_interface_get() in numpy/numpy/core/src/multiarray/getset.c festgelegt werden. Die erste importiert ctypes und erstellt eine numpy.core._internal._ctypes -Instanz, während die zweite ein neues Wörterbuch erstellt und dieses zusätzlich zum Datenzeiger mit vielen unnötigen Daten füllt.

Es gibt nichts, was man auf Python-Ebene über diesen Overhead tun kann, aber man kann ein Mikro-Modul auf der C-Ebene schreiben, das den größten Teil des Overheads umgeht:

%Vor%

Kompilieren Sie wie üblich als Erweiterung in setup.py und importieren Sie als

%Vor%

Bei PyPy wird from accel import _get_ptr fehlschlagen und get_ptr wird auf get_ptr_array zurückgesetzt, was mit Numpypy funktioniert.

Was die Leistung angeht, ist ctypes + accel._get_ptr() für leichte C-Funktionsaufrufe immer noch ein wenig langsamer als die native CPython-Erweiterung, die im Wesentlichen keinen Overhead hat. Es ist natürlich viel schneller als get_ptr_ctypes() und get_ptr_array() oben, so dass der Overhead für mittelschwere C-Funktionsaufrufe unbedeutend werden kann.

Man hat Kompatibilität mit PyPy erlangt, obwohl ich sagen muss, dass ich, nachdem ich ziemlich viel Zeit damit verbracht habe, PyPy für meine wissenschaftlichen Berechnungsanwendungen zu evaluieren, keine Zukunft dafür sehe, solange sie (ziemlich hartnäckig) verweigern die vollständige CPython API zu unterstützen.

Aktualisieren

Ich habe festgestellt, dass ctypes.cast() nun zum Engpass wurde, nachdem accel._get_ptr() eingeführt wurde. Man kann die Umwandlungen loswerden, indem alle Zeiger in der Schnittstelle als ctypes.c_void_p deklariert werden. Das ist, womit ich endete:

%Vor%

Hier verhindert get_ptr_ctypes2() den Cast, indem direkt auf das versteckte Attribut ndarray.ctypes._data zugegriffen wird. Hier sind einige Timing-Ergebnisse für den Aufruf von schweren und leichten C-Funktionen von Python:

%Vor%

Mit accel._get_ptr() und no ctypes.cast() s ist die Geschwindigkeit von ctypes tatsächlich mit einer nativen CPython-Erweiterung konkurrierend. Ich muss also warten, bis jemand h5py , matplotlib und scipy mit ctypes neu schreibt, um PyPy für etwas Ernsthaftes ausprobieren zu können ...

    
Stefan 29.03.2013, 10:07
quelle
0

Das ist vielleicht nicht genug Antwort, aber hoffentlich ein guter Hinweis. Ich verwende scipy.weave.inline () in einigen Teilen meines Codes. Ich weiß nicht viel über die Geschwindigkeit der Schnittstelle selbst, weil die Funktion, die ich ausführe, ziemlich schwer ist und nur auf ein paar Zeiger / Arrays angewiesen ist, aber es scheint mir schnell zu sein. Vielleicht können Sie sich vom scipy.weave Code inspirieren lassen, besonders von attempt_function_call

Ссылка

Wenn Sie sich den C ++ - Code ansehen möchten, der von scipy.weave erzeugt wird,

  1. erzeugt ein einfaches Beispiel von hier: Ссылка ,

  2. Führen Sie das Python-Skript

  3. aus
  4. Ruft den Cache-Ordner "scipy.weave" ab:

    %Vor%
  5. Sehen Sie sich den generierten C ++ Code im Ordner
  6. an
P.R. 28.03.2013 09:47
quelle

Tags und Links