python - Cython 使用内存 View 崩溃

标签 python cython memoryview

当移除gil并使用内存 View 时,出现这个错误:

Fatal Python error: PyThreadState_Get: no current thread

同一个对象以前作为内存 View 运行良好。有关更多详细信息,请参见下面的代码。

# @boundscheck(False)
# @wraparound(False)
# @nonecheck(False)
cpdef c_calculated_mutation(
        np.ndarray[int, ndim=3] population,
        long mutations,
        long[:] depotmap,
        double[:,:] mapping,
        np.ndarray[long, ndim=1] loads,
        dict max_loads,
        np.ndarray[long, ndim=1] durations,
        dict max_durations
):
    cdef:
        int[:,:,:] pop = population
        int xLen = len(population[0][0])
        int yLen = len(population[0])
        int zLen = len(population)
        list export_changes = []
        int x, y, z, xx, yy, i, max_depot, prev, value, mutation
        float new_fitness, best
        int[:,:] view
        int* load_limits     = <int*>malloc(len(max_loads) * sizeof(int))
        int* duration_limits = <int*>malloc(len(max_durations) * sizeof(int))
        int* fxes = <int*>calloc(mutations, sizeof(int))
        int* fyes = <int*>calloc(mutations, sizeof(int))
        int* txes = <int*>calloc(mutations, sizeof(int))
        int* tyes = <int*>calloc(mutations, sizeof(int))
        int* zes  = <int*>calloc(mutations, sizeof(int))
        int* xxx = <int*>calloc(mutations, sizeof(int))
        int* yyy = <int*>calloc(mutations, sizeof(int))
        int* zzz  = <int*>calloc(mutations, sizeof(int))

    i=0
    for value in max_loads:
        load_limits[i] = int(max_loads[value])
        duration_limits[i] = int(max_durations[value])
        max_depot = value
        i += 1

    for mutation in prange(mutations, nogil=True):
        z = rand() % zLen
        y = rand() % yLen
        x = rand() % xLen
        value = population[z, y, x]
        while value >= 0:
            x = rand() % xLen
            value = population[z, y, x]
        xxx[mutation] = x
        yyy[mutation] = y
        zzz[mutation] = z

这就是设置。该错误来自用 gil 注释掉 # 的行。如果我使用 gil,程序会变慢很多。此外,在另一个函数中使用相同的对象作为内存 View 工作得很好。我不明白这一点。

    for mutation in prange(mutations, nogil=True, num_threads=8):
        x = xxx[mutation]
        y = yyy[mutation]
        z = zzz[mutation]

        value = population[z, y, x]
        xx = x
        # with gil:
        best = fitness(pop[z,:,:], xLen, yLen, depotmap, max_depot, mapping, loads, load_limits, durations, duration_limits)
        for yy in range(yLen):
            prev = population[z, yy, xx]
            population[z, yy, xx] = value
            population[z, y,  x ] = prev
            # with gil:
            new_fitness = fitness(pop[z, :, :], xLen, yLen, depotmap, max_depot, mapping, loads, load_limits, durations, duration_limits)
            if best > new_fitness:
                best = new_fitness
                fxes[mutation] = x
                fyes[mutation]  = y
                txes[mutation]  = xx
                tyes[mutation] = yy
                zes[mutation] = z

            population[z, y,  x ] = value
            population[z, yy, xx] = prev

然后是函数的其余部分。

    for mutation in range(mutations):
        x  = fxes[mutation]
        y  = fyes[mutation]
        xx = txes[mutation]
        yy = tyes[mutation]
        z  = zes[mutation]
        export_changes += [z]
        prev = population[z, yy, xx]
        population[z, yy, xx] = population[z, y, x]
        population[z, y,  x ] = prev

    free(load_limits)
    free(duration_limits)
    free(fxes)
    free(fyes)
    free(txes)
    free(tyes)
    free(zes)
    free(xxx)
    free(yyy)
    free(zzz)

    return population, export_changes

最佳答案

loadsdurations类型为 ndarray而不是作为内存 View 。当您将它们传递给函数时,这将需要引用计数,因此不会起作用。不幸的是,Cython 不会在编译时对其进行诊断,因此它只会崩溃。在 c_calculated_mutation 中将它们更改为内存 View 解决问题。这里有一个简短的例子来演示:

cimport numpy as np

# won't allow me to add "nogil" at Cython compile stage
cdef int f(np.ndarray[np.int32_t,ndim=1] x):
    return 1

cdef int g(np.int32_t[:] x) nogil:
    return 2

def call_funcs(np.ndarray[np.int32_t,ndim=1] a, np.int32_t[:] b):
    # can't do "with nogil:" - needs gil to call
    f(a)
    with nogil:
        g(b) # fine
    print("g(b) done")
    with nogil:
        g(a) # crashes

这给出了输出:

g(b) done

Fatal Python error: PyThreadState_Get: no current thread

Current thread 0x00007f3233184540 (most recent call first):

File "<stdin>", line 1 in <module>

Aborted (core dumped)


如果那不能解决问题,可能也可能是内部的东西 fitness因为我们看不到它的内容。它要么需要是 nogil cdef函数(即 cdef int fitness(...) nogil: )或者它需要是 C 函数。

关于python - Cython 使用内存 View 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48780826/

相关文章:

python - pd.date_range 在月底返回起始值,然后继续每月日期?

python - 服务器错误时邮件请求正文以及 Django Admin

c# - 如何将 4 字节字符串编码为单个 32 位整数?

python - Cython:嵌套 typedef 的解决方法

python - cython 路径难以编译 pyx pxd 文件的工作版本

python - Cython:缓冲区类型不匹配,预期为 'int' 但得到了 'long'

python - golang和python中相同字符串的不同字节数组

python - 在 cython 文件中导入任何模块会出现 undefined symbol 错误

python - Cython:优化原生 Python 内存 View

string - 如何在 Python 3 字符串上使用 memoryview?