总是得到“ 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
这只是一个测试。编译时不会发生错误。但是,当我运行测试功能时,会出现错误。我想知道是否有人知道如何解决此问题。我会很感激的。
答案 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