我还没有找到一个完全令人满意的解决办法,但仍然有一些东西我们可以通过在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