Cython - gil相关问题

时间:2015-05-23 22:36:09

标签: python cython

我有以下代码,我正在尝试并行化。描述如下:

# cython: boundscheck=False
# cython: wraparound=False
# cython: cdivision=True

cimport cython
import numpy as np
cimport numpy as cnp
from numpy cimport ndarray as ar

# define a function pointer
ctypedef void (*vector_ptr)(double[:], double, double[:])

cdef void sma_vec(double[:] x, double m, double[:] y) nogil:
    cdef:
        int n
        int mi = int(m)
        Py_ssize_t i, j
    n = x.shape[0]
    for i in range(mi-1, n):
        for j in range(i-mi+1, i+1):
            if j == i-mi+1:
                y[i] = x[j]
            else:
                y[i] += x[j]
        y[i] /= m

cdef void wma_vec(double[:] x, double m, double[:] y) nogil:
    cdef:
        int n
        int mi = int(m)
        Py_ssize_t i, j
    n = x.shape[0]
    for i in range(mi-1, n):
        for j in range(i-mi+1, i+1):
            if j == i-mi+1:
                y[i] = x[j]
            else:
                y[i] += x[j]*float(j-i+m)
        y[i] /= float(m*(m+1))/2.0

cdef void void_vec(double[:] x, double m, double[:] y) nogil:
    pass

cdef vector_ptr stat_switch(stat_func):
    if stat_func == 'sma':
        return &sma_vec
    elif stat_func == 'wma':
        return &wma_vec
    else:
        return &void_vec

cdef double[:] stat_vec(double[:] x, double m, stat_func):
    cdef:
        vector_ptr stat_func_ptr = stat_switch(stat_func)
        double[:] y = x.copy()
    y[:] = np.nan
    stat_func_ptr(x, m, y)
    return y

cdef double[:, ::1] stat_mat(double[:, ::1] x, double m, stat_func):
    cdef:
        vector_ptr stat_func_ptr = stat_switch(stat_func)
        int n
        Py_ssize_t i
        double[:, ::1] y = x.copy()
        double[:] yi
        double[:] xi
    y[:, :] = np.nan
    n = x.shape[1]
    if n > int(m):
        for i in range(0, x.shape[0]):
            yi = y[i, :]
            xi = x[i, :]
            stat_func_ptr(xi, m, yi)
    return y

cdef ar stat_choose(ar x, double m, stat_func):
    if x.ndim == 1:
        return np.asarray(stat_vec(x, m, stat_func))
    elif x.ndim == 2:
        return np.asarray(stat_mat(x, m, stat_func))
    else:
        raise ValueError('Cannot handle more than two dimensions')

cpdef ar sma(ar x, double m):
    return stat_choose(x, m, 'sma')

cpdef ar wma(ar x, double m):
    return stat_choose(x, m, 'wma')

上述代码说明:

  1. 函数sma_vecwma_vec,计算x上的一些指标并返回y中的输出(在此示例中,滚动移动平均线和滚动加权移动平均线)。

  2. 函数stat_switch切换为sma_vecwma_vec,具体取决于stat_func的值,而void_vec是一个无效的虚函数。

  3. 函数stat_vec在一维向量上返回sma_vecwma_vec的输出

  4. 函数stat_mat通过循环遍历二维向量(C类行)的行来返回sma_vecwma_vec的输出

  5. 函数stat_choose检查它是1维np.ndarray还是2维np.ndarray,并相应地将结果重定向到stat_vec或{{1} }

  6. 函数stat_matsma旨在成为wma的python包装器。

  7. 设置文件如下:

    stat_choose

    为了并行化from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext import numpy as np ext_modules = [Extension('movavg1', ['stat/movavg1.pyx'], include_dirs=[np.get_include()], define_macros=[('NPY_NO_DEPRECATED_API', None)], extra_compile_args=['-O3', '-march=native', '-ffast-math'] )] setup( name="Moving Average Functions", cmdclass={'build_ext': build_ext}, ext_modules=ext_modules ) 函数,我有一个循环,我执行以下操作:

    1. 在顶部,我补充道:
    2. stat_mat

      1. from cython.parallel import prange代码更改为(已更改stat_matrange):

        而不是prange,我正在使用range(0, x.shape[0])

      2. 在设置文件中,我向prange(x.shape[0], nogil=True)添加了-fopenmp

        ext_modules

        extra_compile_args=['-O3', '-march=native', '-ffast-math', '-fopenmp'],

      3. 当我尝试编译时,我收到一个错误:

        extra_link_args=['-fopenmp']

        如何将此代码转换为编译它以便Error compiling Cython file: ------------------------------------------------------------ ... n = x.shape[1] if n > int(m): for i in prange(x.shape[0], nogil=True): yi = y[i, :] xi = x[i, :] stat_func_ptr(xi, m, yi) ^ ------------------------------------------------------------ stat\movavg1.pyx:73:25: Calling gil-requiring function not allowed without gil 并行化?

2 个答案:

答案 0 :(得分:0)

尝试更改

ctypedef void (*vector_ptr)(double[:], double, double[:])

ctypedef void (*vector_ptr)(double[:], double, double[:]) nogil

不幸的是,直到明天我才能测试这个。

答案 1 :(得分:0)

ctypedef void (*vector_ptr)(double[:], double, double[:]) nogil

对于Baum mit Augen:当使用函数指针指向nogil函数时,nogil限定符必须是函数指针类型的一部分。只有nogil函数可以在prange块中调用。但是当函数指针类型不包含nogil限定符时,在橙色或nogil块内调用是违法的。