cython prange获取pyeval_savethread错误:null tstate

时间:2018-12-20 21:14:37

标签: python cython

总是得到“ pyeval_savethread:空tstate”的错误

我试图用cython通过prange进行一些并行计算。但是我发现当我使用返回指针的函数时,会出现上述错误。我真的不知道该如何处理。

@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)
cdef double *jonswap(double *w, double Hs, double Tp, int n, double gamma = 3.7) nogil:
    '''
    Function to obtain Jonswap spectra
    w: wave frequency range [rad/s]
    '''
    cdef:
        double *sigma = <double*>malloc(n * sizeof(double))
        double *a = <double*>malloc(n * sizeof(double))
        double fhs = Hs * Hs
        double ftp = Tp * Tp * Tp * Tp
        double wp = 2 * M_PI / Tp
        Py_ssize_t i

    cdef double *sj = <double*>malloc(n * sizeof(double))

    with nogil:
        for i in range(n):
            sigma[i] = 0.07 if w[i] < wp else 0.09
            a[i] = exp(-0.5 * pow((w[i] - wp) / (sigma[i] * w[i]), 2.0))
            sj[i] = 320 * fhs * pow(w[i], -5.0) / ftp * exp(-1950 * pow(w[i], -4) / ftp) * pow(gamma, a[i])



    free(sigma)
    free(a)

    return sj

def test():
    cdef:
        double dw = 0.05
        int n = 43
        int i = 0
        double *w = <double*>malloc(n * sizeof(double))
        double Hs = 3.0
        double Tp = 8.0

    for i in range(n):
        w[i] = 0.35 + i * dw

    # initialize Jonswap spectra and wave elevation
    cdef:
        double *S_wave
        int j
        double suma = 0.0
        # double[:] z = np.zeros((n), dtype=DTYPE_float)

    with nogil, parallel():
        S_wave = jonswap(w, Hs, Tp, n)
        for i in prange(100, schedule='guided'):            
            suma += sumw(S_wave,n)
        free(S_wave)

    return suma

cdef double sumw(double *s, int n) nogil:
    cdef:
        int i
        double suma = 0
    for i in range(n):
        suma += s[i]

    return suma

这只是一个测试。编译时不会发生错误。但是,当我运行测试功能时,会出现错误。我想知道是否有人知道如何解决此问题。我会很感激的。

1 个答案:

答案 0 :(得分:0)

由于您的示例不完整,因此我创建了一个更简单的示例,该示例证实了我最初的想法,即问题与nogil函数内的nogil块有关:

cdef int f(int x) nogil:
    cdef int y
    with nogil:
        y = x+1 # do some work without the GIL
    return x

def test():
    cdef int out
    with nogil:
        out = f(1)

给予:

  

致命的Python错误:PyEval_SaveThread:NULL tstate

问题是,with nogil中包含f块会在您不按住GIL时尝试释放GIL,或者当它不应该在块末尾尝试重新获得GIL时,做。解决方案是删除不必要的with nogil:块(在这种情况下,在f内部,在您的情况下,在jonswap内部)

理想情况下,Cython应该将此标记为错误。


编辑:一项简化的测试,显示您可以在并行块中返回指针而没有错误。它没什么用。

from libc.stdlib cimport malloc, free

from cython.parallel import prange, parallel


def test():
    cdef:
        double *S_wave
        int i
        double suma = 0
        int n = 50

    with nogil, parallel():
        S_wave = allocate(n)
        for i in prange(100):
            suma += sumw(S_wave,n)
        free(S_wave)

    print(suma)

cdef double sumw(double *s, int n) nogil:
    cdef:
        int i
        double suma = 0
    for i in range(n):
        suma += s[i]

    return suma

cdef double* allocate(int n) nogil:
    cdef double* out = <double*>malloc(sizeof(double)*n)
    cdef int i
    for i in range(n):
        out[i] = i*0.5
    return out