当两个用户同时运行C扩展时,Django崩溃

2024-10-04 05:22:46 发布

您现在位置:Python中文网/ 问答频道 /正文

问题摘要

我正在Django中调用我自己的Python C扩展,它负责一些长时间的计算。该扩展运行良好,甚至用户在C扩展进行计算时也可以浏览Django应用程序,因为我在扩展中实现了全局解释器锁(GIL)管理。但是,当另一个用户尝试执行扩展时(当它为初始用户运行时),Django崩溃(进程被终止),并且没有任何错误消息

代码示例

在下面的代码中,您可以看到Django视图,它(通过请求POST)调用C扩展ftaCalculate

import ftaCalculate
from django.views.generic.base import TemplateView

# Computation
class ComputationView(TemplateView):
    template_name = 'Generic/computation_page.html'

    @staticmethod
    def get_results(request):
        if request.method == "POST":  # When button is pressed
            # Long computations
            cs_min = ftaCalculate.mcs(N, tree)
        else:
            cs_min = None
        return render(request, ComputationView.template_name, {'cs_min': cs_min})

当两个用户并行运行函数ftaCalculate.mcs时,Django崩溃。我将在下文中介绍C代码的主要功能。函数comb的内部是我使用Py_BEGIN_ALLOW_THREADSPy_END_ALLOW_THREADS的地方

// Compute the Minimal cutsets
PyObject* Cmcs(int n, PyObject* tree)
{
    // Initialize cs_all
    cs_all = NULL;

    // Get the leaves of the FTA (pointer)
    PyObject *leaf_seq = PyObject_GetAttrString(tree, "leafs");
    int n_comb = PyObject_Length(leaf_seq);

    // All possible combinations of boolean values
    int *indeces = (int *)malloc(n_comb * sizeof(int));

    // Initialize mcs_index
    ArrayInt num_mcs_index;
    initArrayInt(&num_mcs_index, 1);
    ArrayArray mcs_index;
    initArrayArray(&mcs_index, 1, n_comb);

    // String buffer for 0s/1s
    int* str_buff = (int*) malloc(n_comb * sizeof(int));
    int ind_str = 0;

    // Get the combination
    comb(n_comb, n, str_buff, ind_str, n_comb, 0, leaf_seq, indeces, &num_mcs_index, &mcs_index, tree);
    free(str_buff);
    str_buff=NULL;
    free(indeces);
    indeces=NULL;

    // Order the cutsets
    // Order the cutset by its count
    HASH_SORT(cs_all, val_sort);

    // Make array without redundant cutsets
    PyObject *cs_all_sorted_readable = PyList_New(0);
    
    struct my_struct *current_user, *tmp = NULL;
    const char *cutset_name = NULL;
    HASH_ITER(hh, cs_all, current_user, tmp) {
        cutset_name = current_user->name;
        PyObject *result_array= PyList_New(0);
        for(int i = 0; cutset_name[i] != '\0'; i++) {
            if(cutset_name[i] == '1'){
                PyObject * str_int = PyObject_Str(PyList_GetItem(leaf_seq, i));
                PyList_Append(result_array, str_int);
                Py_XDECREF(str_int);
            }    
        }
        PyList_Append(cs_all_sorted_readable, result_array);
        
        // Free allocated memory space
        Py_CLEAR(result_array);
    }
    free(cutset_name);
    cutset_name = NULL;
    /*free(current_user);
    free(tmp);*/

    // Free allocated memory space
    delete_all(cs_all);  /* free any structures */
    freeArrayInt(&num_mcs_index);
    freeArrayArray(&mcs_index);
    Py_CLEAR(leaf_seq);
    
    return cs_all_sorted_readable;
}

// Our Python binding to our C function
// This will take one and only one non-keyword argument
static PyObject* mcs(PyObject* self, PyObject* args)
{
    // instantiate the expected arguments
    int n; // Order of cutset
    PyObject *cb; // Tree object

    // Parse the arguments
    if(!PyArg_ParseTuple(args, "iO", &n, &cb))
        return NULL;

    // Determine whether the object has the expected structure
    if (!PyObject_HasAttrString(cb, "pk")) {
        PyErr_SetString(PyExc_TypeError, "mcs: the object structure is not the expected one");
        return 0;
    }

    // Function to return the result back to Python
    PyObject* result_cms = Cmcs(n, cb);

    if(result_cms==NULL){
        PyErr_SetString(PyExc_TypeError, "mcs: the returned object is null");
        return NULL;
    }

    return result_cms;
}



// Our Module's Function Definition struct
// We require this `NULL` to signal the end of our method
// definition
static PyMethodDef myMethods[] = {
    { "mcs", mcs, METH_VARARGS | METH_KEYWORDS, "Computes Minimal Cutsets" },
    { NULL, NULL, 0, NULL }
};

// Our Module Definition struct
static struct PyModuleDef ftaCalculate = {
    PyModuleDef_HEAD_INIT,
    "ftaCalculate",
    "Test Module",
    -1,
    myMethods
};

// Initializes our module using our above struct
PyMODINIT_FUNC PyInit_ftaCalculate(void)
{
    return PyModule_Create(&ftaCalculate);
}

问题:

这种行为发生是正常的还是我遗漏了一些需要在C扩展中实现的东西


Tags: thenameindexreturnresultallcsnull