You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Python C API高效传递大量数据?

批量从C向Python传递大数据的最优方案

针对百万级double类型数据的批量传递,核心思路是利用**缓冲区协议(Buffer Protocol)**直接共享或批量写入数据,避免逐个创建PyObject的巨大开销。以下是几种实用方案:

方案1:使用Python标准库array模块

array.array原生支持缓冲区协议,能直接将C中的连续内存块写入,无需逐个元素调用API。

C代码示例

#include <Python.h>
#include <arrayobject.h>
#include <string.h>

PyObject* pass_large_doubles(double* data, size_t count) {
    // 导入array模块
    PyObject* array_module = PyImport_ImportModule("array");
    if (!array_module) return NULL;

    // 获取array.array类
    PyObject* array_type = PyObject_GetAttrString(array_module, "array");
    Py_DECREF(array_module);
    if (!array_type) return NULL;

    // 创建array对象,类型码'd'对应double
    PyObject* args = PyTuple_New(1);
    PyTuple_SetItem(args, 0, PyUnicode_FromString("d"));
    PyObject* array_obj = PyObject_CallObject(array_type, args);
    Py_DECREF(args);
    Py_DECREF(array_type);
    if (!array_obj) return NULL;

    // 获取缓冲区
    Py_buffer view;
    if (PyObject_GetBuffer(array_obj, &view, PyBUF_WRITABLE | PyBUF_FORMAT) != 0) {
        Py_DECREF(array_obj);
        return NULL;
    }

    // 确保缓冲区类型匹配
    if (strcmp(view.format, "d") != 0) {
        PyBuffer_Release(&view);
        Py_DECREF(array_obj);
        PyErr_SetString(PyExc_TypeError, "Array format mismatch");
        return NULL;
    }

    // 调整array大小以容纳数据
    PyObject* resize_method = PyObject_GetAttrString(array_obj, "resize");
    if (!resize_method) {
        PyBuffer_Release(&view);
        Py_DECREF(array_obj);
        return NULL;
    }
    args = PyTuple_New(1);
    PyTuple_SetItem(args, 0, PyLong_FromSize_t(count));
    PyObject_CallObject(resize_method, args);
    Py_DECREF(args);
    Py_DECREF(resize_method);

    // 重新获取缓冲区(resize后可能地址变化)
    PyBuffer_Release(&view);
    if (PyObject_GetBuffer(array_obj, &view, PyBUF_WRITABLE | PyBUF_FORMAT) != 0) {
        Py_DECREF(array_obj);
        return NULL;
    }

    // 批量拷贝数据
    memcpy(view.buf, data, count * sizeof(double));

    // 释放缓冲区
    PyBuffer_Release(&view);

    return array_obj;
}

方案2:使用numpy数组(推荐用于高性能场景)

numpy的C API支持直接从C内存创建数组,开销极低,适合超大规模数据。

C代码示例

#include <Python.h>
#include <numpy/arrayobject.h>

PyObject* pass_large_doubles_to_numpy(double* data, size_t count, int should_own) {
    // 初始化numpy C API
    import_array();

    // 指定数组维度:1维,长度为count
    npy_intp dims[1] = {count};
    // 创建数组,NPY_DOUBLE对应double类型
    PyObject* np_array = PyArray_SimpleNewFromData(
        1, dims, NPY_DOUBLE, data
    );
    if (!np_array) return NULL;

    // 如果需要numpy接管内存(避免C侧手动释放),设置OWNDATA标志
    if (should_own) {
        ((PyArrayObject*)np_array)->flags |= NPY_ARRAY_OWNDATA;
    }

    return np_array;
}

注意:如果设置should_own=1,后续numpy会负责释放data内存,C侧不能再手动free;否则需要C侧自行管理内存生命周期。

方案3:自定义缓冲区对象(灵活扩展)

如果需要更定制化的内存管理,可自定义一个实现缓冲区协议的PyObject类型,让Python直接访问C中的原始数据:

核心结构示例

typedef struct {
    PyObject_HEAD
    double* data;
    size_t count;
    int own_data;
} CustomBufferObject;

// 实现bf_getbuffer方法
static int custom_buffer_getbuffer(PyObject* self, Py_buffer* view, int flags) {
    CustomBufferObject* obj = (CustomBufferObject*)self;
    return PyBuffer_FillInfo(
        view, self, obj->data, obj->count * sizeof(double),
        0, flags  // 0表示数据是C顺序
    );
}

// 实现bf_releasebuffer方法
static void custom_buffer_releasebuffer(PyObject* self, Py_buffer* view) {
    // 若需要,在这里释放内存
    CustomBufferObject* obj = (CustomBufferObject*)self;
    if (obj->own_data) {
        free(obj->data);
        obj->data = NULL;
    }
}

// 类型定义
static PyBufferProcs custom_buffer_as_buffer = {
    custom_buffer_getbuffer,
    custom_buffer_releasebuffer
};

static PyTypeObject CustomBufferType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "custombuffer.CustomBuffer",
    .tp_basicsize = sizeof(CustomBufferObject),
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_BUFFER,
    .tp_as_buffer = &custom_buffer_as_buffer,
    // 省略其他方法(如__dealloc__)
};

这三种方案都能避免百万次API调用,其中numpy方案性能最优,array方案无需额外依赖,自定义方案适合特殊内存管理需求。

内容的提问来源于stack exchange,提问作者Boulder_on

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 20:50:26