gpt4 book ai didi

python - 如何在 Cython 的新型缓冲区对象中包装 C 指针和长度?

转载 作者:太空狗 更新时间:2023-10-29 21:43:00 26 4
gpt4 key购买 nike

我正在用 Cython 编写 Python 2.7 扩展模块。 我如何创建一个 Python 对象来实现新式缓冲区接口(interface),该接口(interface)包装了 C 库提供给我的内存块?内存块只是一串字节,而不是结构或多维数组。我得到了一个 const void * 指针和一个长度,以及有关指针保持有效时间的一些详细信息。

我无法复制内存——这会降低我的应用程序的性能。

对于旧式缓冲区对象,我可以简单地使用 PyBuffer_FromMemory(),但我似乎找不到一种类似的简单方法来生成新式缓冲区对象。

我是否必须创建自己的类来实现缓冲区接口(interface)?或者 Cython 是否提供了一种简单的方法来做到这一点?

我读过 Unicode and Passing StringsTyped Memoryviews来自 Cython 文档的页面,但该文档不精确且不是很完整,并且没有看起来与我想要做的相似的示例。

这是我尝试过的 (test.pyx):

from libc.stdlib cimport malloc
from libc.string cimport memcpy

## pretend that this function is in some C library and that it does
## something interesting. (this function is unrelated to the problem
## I'm experiencing -- this is just an example function that returns a
## chunk of memory that I want to wrap in an object that follows the
## new buffer protocol.)
cdef void dummy_function(const void **p, size_t *l):
cdef void *tmp = malloc(17)
memcpy(tmp, "some test\0 bytes", 17)
p[0] = tmp
l[0] = 17

cpdef getbuf():
cdef const void *cstr
cdef size_t l
dummy_function(&cstr, &l)

## error: test.pyx:21:20: Invalid base type for memoryview slice: void
#cdef const void[:] ret = cstr[:l]

## error: test.pyx:24:9: Assignment to const 'ret'
#cdef const char[:] ret = cstr[:l]

## error: test.pyx:27:27: Cannot convert 'void const *' to memoryviewslice
#cdef char[:] ret = cstr[:l]

## this next attempt cythonizes, but raises an exception:
## $ python -c 'import test; test.getbuf()'
## Traceback (most recent call last):
## File "<string>", line 1, in <module>
## File "test.pyx", line 15, in test.getbuf (test.c:1411)
## File "test.pyx", line 38, in test.getbuf (test.c:1350)
## File "stringsource", line 614, in View.MemoryView.memoryview_cwrapper (test.c:6763)
## File "stringsource", line 321, in View.MemoryView.memoryview.__cinit__ (test.c:3309)
## BufferError: Object is not writable.
cdef char[:] ret = (<const char *>cstr)[:l]

## this raises the same exception as above
#cdef char[:] ret = (<char *>cstr)[:l]

return ret

最佳答案

您可以定义一个 extension type通过定义 __getbuffer____releasebuffer__ 实现缓冲协议(protocol) special methods .例如:

from cpython.buffer cimport PyBuffer_FillInfo
from libc.stdlib cimport free, malloc
from libc.string cimport memcpy

cdef void dummy_function(const void **p, size_t *l):
cdef void *tmp = malloc(17)
memcpy(tmp, "some test\0 bytes", 17)
p[0] = tmp
l[0] = 17

cdef void free_dummy_data(const void *p, size_t l, void *arg):
free(<void *>p)

cpdef getbuf():
cdef const void *p
cdef size_t l
dummy_function(&p, &l)
return MemBuf_init(p, l, &free_dummy_data, NULL)

ctypedef void dealloc_callback(const void *p, size_t l, void *arg)

cdef class MemBuf:
cdef const void *p
cdef size_t l
cdef dealloc_callback *dealloc_cb_p
cdef void *dealloc_cb_arg

def __getbuffer__(self, Py_buffer *view, int flags):
PyBuffer_FillInfo(view, self, <void *>self.p, self.l, 1, flags)
def __releasebuffer__(self, Py_buffer *view):
pass

def __dealloc__(self):
if self.dealloc_cb_p != NULL:
self.dealloc_cb_p(self.p, self.l, self.dealloc_cb_arg)

# Call this instead of constructing a MemBuf directly. The __cinit__
# and __init__ methods can only take Python objects, so the real
# constructor is here. See:
# https://mail.python.org/pipermail/cython-devel/2012-June/002734.html
cdef MemBuf MemBuf_init(const void *p, size_t l,
dealloc_callback *dealloc_cb_p,
void *dealloc_cb_arg):
cdef MemBuf ret = MemBuf()
ret.p = p
ret.l = l
ret.dealloc_cb_p = dealloc_cb_p
ret.dealloc_cb_arg = dealloc_cb_arg
return ret

通过上面的代码(名为 test.pyx),您将获得以下行为:

$ python -c 'import test; print repr(memoryview(test.getbuf()).tobytes())'
'some test\x00 bytes\x00'

不知道有没有更简单的方法。

关于python - 如何在 Cython 的新型缓冲区对象中包装 C 指针和长度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28160359/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com