我正在开发一个Python C扩展模块(用于CPython 2.5)。它调用一些填充缓冲区的底层网络API。
目前代码的编写基本如下:
PyObject * buffer;
char * cbuf;
size_t buffer_size = 1024;
int sz;
buffer = PyString_FromStringAndSize(NULL, buffer_size);
if (buffer == NULL) return NULL;
cbuf = PyString_AsString(buffer);
Py_BEGIN_ALLOW_THREADS
sz = read(cbuf, buffer_size);
Py_END_ALLOW_THREADS
if (sz > 0 && sz != buffer_size && _PyString_Resize(&buffer, sz) < 0)
return NULL;
据我所知,这段代码运行正常,但我想知道_PyString_Resize
的内部结构。如果sz小于buffer_size,它是否使用现有缓冲区重新分配内存?
从效率的角度来看,我可能更喜欢前者避免使用缓冲内容的无用副本,即使它消耗的内存超过了必要的内存。另一方面,重新分配内存也可能会减少内存占用。
那么_PyString_Resize会做哪一个?是否有一种简单的方法来控制这种行为?
答案 0 :(得分:3)
是的,_PyString_Resize
执行realloc
- 毕竟,这就是您要求它做的事情: - )
如果要保存重新分配,也许可以read
进入堆栈上的缓冲区,然后从中创建字符串对象。像(没有编译和测试,所以把它当作伪代码):
char cbuf[BUFFER_SIZE];
int sz = read(cbuf, BUFFER_SIZE);
PyObject * buffer = PyString_FromStringAndSize(cbuf, sz);
另外,请注意_PyString_Resize
(Objects/stringobject.c
)的实施上方的警告:
以下函数打破了字符串不可变的概念:
它会改变字符串的大小。我们 只有有了这个才能逃脱 只有一个模块引用了 宾语。你也可以把它想象成创建一个新的字符串对象和 摧毁旧的,只有更有效率。无论如何,请勿使用 如果字符串可能已经为代码的其他部分所知......