【问题标题】:why python-extension function breaks when creating array of structs with length greater than 4?为什么 python-extension 函数在创建长度大于 4 的结构数组时会中断?
【发布时间】:2019-07-08 18:07:36
【问题描述】:

我正在用 C 语言编写一个 python 扩展模块。当我在该模块的函数中声明一个结构数组大于 4 个元素时,Python 停止运行。

我正在编写模块以提高性能。 我已经声明了 3 个结构(“SKU”、“Cromosoma”、“Aptitud”)并且我想创建一个 Cromosoma 数组,但是当我尝试创建包含 4 个以上元素的数组时它会中断。

// need_for_speed.c   extension module code
#include <Python.h>
#include <stdlib.h>
#define MAX_GENES_SIZE  2000
typedef struct{
    char codigo[30];
    double venta;
    char nombre[100];
    double categoria;
    double peso;
    double ubicacion_especifica;
    double ubicacion_actual;
    double ubicacion_a_mover;
    double stock;
} SKU;
typedef struct{
    double ubicaciones_rompe_regla;
    double cercania_medio;
    double desv_std_picks_x_seccion;
    double peso_x_ubicacion;
} Aptitud;
typedef struct{
    SKU genes[MAX_GENES_SIZE];
    Aptitud aptitud;
    int genes_size;
    int edad;
}Cromosoma;

static PyObject* prueba(PyObject* self, PyObject* args){
    Cromosoma a;
    SKU s;
    strcpy(s.codigo,"1212");
    a.genes[0] = s;
    Cromosoma poblacion[] = {a,a,a,a,a};
    printf("codigo %s ", poblacion[0].genes[0].codigo);
    return PyLong_FromDouble(1);
}
static PyMethodDef Methods[] = {
    {"prueba", prueba, METH_NOARGS, "Prueba general"},
    { NULL, NULL, 0, NULL }
};

// Module Definition struct
static struct PyModuleDef need_for_speed = {
    PyModuleDef_HEAD_INIT,
    "need_for_speed",
    "Modulo para aumento de la velocidad de procesamiento para el algoritmo genético",
    -1,
    Methods
};

// Initialize module 
PyMODINIT_FUNC PyInit_need_for_speed(void)
{
    PyObject *m;
    m = PyModule_Create(&need_for_speed);
    return m;
}

用于构建此模块的 setup.py:

from distutils.core import setup, Extension
setup(name = 'need_for_speed', version = '1.0',ext_modules = [Extension('need_for_speed', ['need_for_speed.c'])])

构建模块的命令:

python setup.py build

当我调用函数 prueba 时:

import need_for_speed
i = need_for_speed.prueba()

python 在不打印或返回任何内容的情况下停止运行,但如果在“prueba”函数中修改名为“poblacion”的数组,使其只有 4 个元素,它将完美运行,返回 1 并打印“codigo 1212”。

顺便说一句,我使用的是 Windows。

【问题讨论】:

  • 我认为没有理由相信所提供的代码对所描述的行为负责,即使我们规定通过将缺少的 } 插入到Cromosoma 类型定义。至少与数组无关。我们需要善意 minimal reproducible example 来确定可能发生的情况。
  • 抱歉缺少 } 和最小可重现示例所需的缺少代码。我刚刚编辑了它。

标签: python c arrays


【解决方案1】:

可能是stack overflow

让我们看看你的结构有多大,假设它们只占用单个成员的大小(忽略填充等):

  • SKU: 7 个双精度和 130 个字符 -> 7 * 8 个字节 + 130 个字节 -> 186 个字节
  • Aptitud: 4 双 -> 4 * 8 字节 -> 32 字节
  • Cromosoma:2 个整数、1 个 Aptitud 和 2000 个 SKU -> 2 * 4 字节 + 32 字节 + 2000 * 186 字节 -> 372040 字节

所以Chromosoma 的一个实例将占用大约 370kB。你创造了其中的 5/6;一个带有Cromosoma a;,一个用于阵列中的每个插槽:4/5。

典型的堆栈只有几兆字节。对于 6 * 370kB ~ 2.1MB,你用尽你的堆栈至少是合理的。例如 MSVC(Windows Visual Studio C/C++ 编译器)默认只使用1 MB。鉴于它使用大小为 5 的数组失败,但可以使用大小为 4 的数组,看来您有大约 2 MB 的堆栈。

为避免此问题,您可以增加堆栈大小(具体如何操作取决于您的编译器)。但是,当您需要更多 Chromosoma 或更改 SKUs 的数量时,增加堆栈大小会再次导致问题。

另一种选择(可能比增加堆栈大小更好)是在堆上分配所有大数组。例如,您可以在堆上分配poblacion - 和/或使Chromosoma.genes 成为指向SKU 数组的指针。

【讨论】:

    猜你喜欢
    • 2013-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    • 1970-01-01
    • 2020-01-05
    • 2020-09-04
    • 1970-01-01
    相关资源
    最近更新 更多