扩展模块:将 void * 编组为 bytearray(and/or 反之亦然)
Extension modules: marshalling void * to bytearray (and/or vice versa)
使用 python
(意味着 python3
)做一些实验来准备数据(也将它们发送到线路 - SPI)表明它很慢(系统受限)。所以我正在考虑创建用 C
编写的扩展模块,以将关键内容推迟到。我想要:
python
脚本可以访问由扩展模块中的 malloc()
创建的内存块,希望可以透明地转换为 bytearray
- 扩展模块将获得指向在
python
中创建的 bytearray
对象的指针,希望可以透明地转换为 void *
目标是零拷贝也作为零转换内存块,可供python
(如bytearray
)和扩展模块(如void *
)访问。
请问有什么方法,如何实现的?
好的,看起来比想象中的要简单 ;-)
bytearray
直接支持访问底层内存块,正是需要的
- 有一个用于从函数调用参数列表中提取
bytearray
对象的格式说明符
C扩展模块[test.c
]:
#include <Python.h>
#include <stdint.h>
/* Forward prototype declaration */
static PyObject *transform(PyObject *self, PyObject *args);
/* Methods exported by this extension module */
static PyMethodDef test_methods[] =
{
{"transform", transform, METH_VARARGS, "testing buffer transformation"},
{NULL, NULL, 0, NULL}
};
/* Extension module definition */
static struct PyModuleDef test_module =
{
PyModuleDef_HEAD_INIT,
"BytearrayTest",
NULL,
-1,
test_methods,
};
/*
* The test function
*/
static PyObject *transform(PyObject *self, PyObject *args)
{
PyByteArrayObject *byte_array;
uint8_t *buff;
int buff_len = 0;
int i;
/* Get the bytearray object */
if (!PyArg_ParseTuple(args, "Y", &byte_array))
return NULL;
buff = (uint8_t *)(byte_array->ob_bytes); /* data */
buff_len = byte_array->ob_alloc; /* length */
/* Perform desired transformation */
for (i = 0; i < buff_len; ++i)
buff[i] += 65;
/* Return void */
Py_INCREF(Py_None);
return Py_None;
}
/* Mandatory extension module init function */
PyMODINIT_FUNC PyInit_BytearrayTest(void)
{
return PyModule_Create(&test_module);
}
C扩展模块build/deployment脚本[setup.py
]:
#!/usr/bin/python3
from distutils.core import setup, Extension
module = Extension('BytearrayTest', sources = ['test.c'])
setup (name = 'BytearrayTest',
version = '1.0',
description = 'This is a bytearray test package',
ext_modules = [module])
Build/install扩展模块:
# ./setup.py build
# ./setup.py install
测试一下:
>>> import BytearrayTest
>>> a = bytearray(16); a
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
>>> BytearrayTest.transform(a); a
bytearray(b'AAAAAAAAAAAAAAAA')
>>>
使用 python
(意味着 python3
)做一些实验来准备数据(也将它们发送到线路 - SPI)表明它很慢(系统受限)。所以我正在考虑创建用 C
编写的扩展模块,以将关键内容推迟到。我想要:
python
脚本可以访问由扩展模块中的malloc()
创建的内存块,希望可以透明地转换为bytearray
- 扩展模块将获得指向在
python
中创建的bytearray
对象的指针,希望可以透明地转换为void *
目标是零拷贝也作为零转换内存块,可供python
(如bytearray
)和扩展模块(如void *
)访问。
请问有什么方法,如何实现的?
好的,看起来比想象中的要简单 ;-)
bytearray
直接支持访问底层内存块,正是需要的- 有一个用于从函数调用参数列表中提取
bytearray
对象的格式说明符
C扩展模块[test.c
]:
#include <Python.h>
#include <stdint.h>
/* Forward prototype declaration */
static PyObject *transform(PyObject *self, PyObject *args);
/* Methods exported by this extension module */
static PyMethodDef test_methods[] =
{
{"transform", transform, METH_VARARGS, "testing buffer transformation"},
{NULL, NULL, 0, NULL}
};
/* Extension module definition */
static struct PyModuleDef test_module =
{
PyModuleDef_HEAD_INIT,
"BytearrayTest",
NULL,
-1,
test_methods,
};
/*
* The test function
*/
static PyObject *transform(PyObject *self, PyObject *args)
{
PyByteArrayObject *byte_array;
uint8_t *buff;
int buff_len = 0;
int i;
/* Get the bytearray object */
if (!PyArg_ParseTuple(args, "Y", &byte_array))
return NULL;
buff = (uint8_t *)(byte_array->ob_bytes); /* data */
buff_len = byte_array->ob_alloc; /* length */
/* Perform desired transformation */
for (i = 0; i < buff_len; ++i)
buff[i] += 65;
/* Return void */
Py_INCREF(Py_None);
return Py_None;
}
/* Mandatory extension module init function */
PyMODINIT_FUNC PyInit_BytearrayTest(void)
{
return PyModule_Create(&test_module);
}
C扩展模块build/deployment脚本[setup.py
]:
#!/usr/bin/python3
from distutils.core import setup, Extension
module = Extension('BytearrayTest', sources = ['test.c'])
setup (name = 'BytearrayTest',
version = '1.0',
description = 'This is a bytearray test package',
ext_modules = [module])
Build/install扩展模块:
# ./setup.py build
# ./setup.py install
测试一下:
>>> import BytearrayTest
>>> a = bytearray(16); a
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
>>> BytearrayTest.transform(a); a
bytearray(b'AAAAAAAAAAAAAAAA')
>>>