Cython аварийно завершал работу, используя memoryviews

При удалении гила и использовании просмотра памяти появляется такая ошибка:

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

Это была установка. Баг возникает из-за строк с закомментированным # с гилом. Если я использую гил, программа сильно тормозит. Кроме того, использование того же объекта в качестве представления памяти в другой функции прекрасно работает. Я не понимаю.

    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

person Magnus Wang    schedule 14.02.2018    source источник


Ответы (1)


loads и durations вводятся как ndarray, а не как представления памяти. Когда вы передаете их функции, это потребует подсчета ссылок и поэтому не будет работать. К сожалению, Cython не диагностирует его во время компиляции, поэтому он просто падает. Измените их на memoryviews в c_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.

person DavidW    schedule 14.02.2018
comment
Извините за удаленный / восстановленный ответ - потребовалось несколько попыток, чтобы действительно выбрать правильный вопрос. Это точно воспроизводит вашу ошибку, поэтому я уверен, что это правильно - person DavidW; 15.02.2018