简体   繁体   中英

cython prange get error of pyeval_savethread: null tstate

always get error of "pyeval_savethread: null tstate"

I tried to use cython to do some parallel computing by prange. But I found when I use the function which returns pointer, I will get the above error. I really don't have any idea how to deal with that.

@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

it is just a test. No error occurs when compiled. But when I run test function it get the error. I am wondering if anyone knows how this can be fixed. I'll really appreciate that.

Since your example is incomplete I created a simpler one which confirms my initial thought that the problem is related to a nogil block inside a nogil function:

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)

Giving:

Fatal Python error: PyEval_SaveThread: NULL tstate

The issue is either that with with nogil block inside f tries to release the GIL when you don't hold it, or it tries to regain it at the end of the block when it shouldn't do. The solution is to remove the unnecessary with nogil: block (in this case inside f , in your case inside jonswap )

Ideally Cython should probably flag this as an error.


Edit: a simplified test that shows you can return pointers in a parallel block without error. It doesn't do anything much useful.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM