我還沒有找到一個完全令人滿意的解決辦法,但仍然有一些東西我們可以通過在CPython中獲得更少的開銷來獲得指針。首先,上述兩種方式如此之慢的原因是.ctypes
和.__array_interface__
都是按需屬性,其由array_ctypes_get()
和array_interface_get()
在numpy/numpy/core/src/multiarray/getset.c
中設置。第一個導入ctypes並創建一個numpy.core._internal._ctypes
實例,而第二個創建一個新的字典,並在數據指針之外添加大量不必要的東西。
沒有什麼人能在這個開銷Python層面做,但可以寫在C級的微型模塊繞過大部分的開銷:
#include <Python.h>
#include <numpy/arrayobject.h>
PyObject *_get_ptr(PyObject *self, PyObject *obj) {
return PyLong_FromVoidPtr(PyArray_DATA(obj));
}
static PyMethodDef methods[] = {
{"_get_ptr", _get_ptr, METH_O, "Wrapper to PyArray_DATA()"},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initaccel(void) {
Py_InitModule("accel", methods);
}
正常編譯就可以作爲擴展在setup.py
,進口爲
try:
from accel import _get_ptr
def get_ptr(x):
return C.cast(_get_ptr(x), p_t)
except ImportError:
get_ptr = get_ptr_array
在PyPy,from accel import _get_ptr
將失敗,get_ptr
將回落至get_ptr_array
,這與Numpypy工作。
就性能而言,對於輕量級的C函數調用,ctypes + accel._get_ptr()
仍然比本地CPython擴展慢很多,後者基本沒有開銷。它當然比上面的get_ptr_ctypes()
和get_ptr_array()
快得多,因此對於中等重量的C函數調用來說開銷可能變得不重要。
一個已經獲得了兼容PyPy,但我不得不說,花費相當多的時間試圖評估PyPy我的科學計算應用程序後,我沒有看到它的未來,只要他們(相當固執地)拒絕支持完整的CPython API。
更新
我發現,現在ctypes.cast()
變得引進accel._get_ptr()
後的瓶頸。通過將接口中的所有指針聲明爲ctypes.c_void_p
,可以擺脫這些強制轉換。這是我結束了:
def get_ptr_ctypes2(x):
return x.ctypes._data
def get_ptr_array(x):
return x.__array_interface__['data'][0]
try:
from accel import _get_ptr as get_ptr
except ImportError:
get_ptr = get_ptr_array
這裏,get_ptr_ctypes2()
通過直接訪問隱藏ndarray.ctypes._data
屬性避免了演員。下面是用於調用重的重量和重量輕的C函數在Python一些時序結果:
heavy C (few calls) light C (many calls)
ctypes + get_ptr_ctypes(): 0.71 s 15.40 s
ctypes + get_ptr_ctypes2(): 0.68 s 13.30 s
ctypes + get_ptr_array(): 0.65 s 11.50 s
ctypes + accel._get_ptr(): 0.63 s 9.47 s
native CPython: 0.62 s 8.54 s
Cython (no decorators): 0.64 s 9.96 s
所以,用accel._get_ptr()
和無ctypes.cast()
S,ctypes的是速度與天然CPython的延伸實際上具有競爭力。所以,我只是要等到有人改寫h5py
,matplotlib
和scipy
與ctypes的是能夠嘗試PyPy對於事情的嚴重性...
不幸的是,'scipy.weave'確實沒有什麼比產生使用CPython的API的C代碼其他( '#include'),這不會與'PyPy'一起使用。在CPython API中,'PyArray_DATA()'是獲得指向numpy數組數據部分的指針的最有效方法,但它不可移植到PyPy。 –
Stefan
2013-03-28 10:19:32