4

移除 gil 并使用内存视图时,会出现此错误:

Fatal Python error: PyThreadState_Get: no current thread

同一个对象以前作为内存视图工作得很好。有关更多详细信息,请参见下面的代码。

# @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,程序会变慢很多。此外,在另一个函数中使用相同的对象作为内存视图也可以很好地工作。我不明白这一点。

    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
4

1 回答 1

3

loads并且durations被键入ndarray而不是 memoryviews。当您将它们传递给函数时,这将需要引用计数,因此不起作用。不幸的是,Cython 没有在编译时诊断它,所以它只是崩溃了。将它们更改为 memoryviewsc_calculated_mutation以解决问题。这是一个简短的示例来演示:

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 函数。

于 2018-02-14T07:11:39.347 回答