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.