Я работаю над модулем расширения 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? И есть ли простой способ контролировать такое поведение?
Да, _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
):
Следующая функция нарушает представление о том, что строки неизменяемы:
он изменяет размер строки. Мы избегайте этого, только если есть только один модуль, ссылающийся на объект. Вы также можете подумать о создании нового строкового объекта и разрушая старый, только более эффективно. В любом случае не используйте это, если строка уже может быть известна какой-либо другой части кода...