2015-05-23 51 views
4

我有以下代码,我试图并行化。下面的描述的代码Cython - gil相关问题

# 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,计算相关数据超过xy返回输出(在该示例中,滚动移动平均和滚动加权移动平均数)。

  2. 功能stat_switch开关要么sma_vecwma_vec取决于的stat_funcvoid_vec的值是一个伪函数什么都不做。

  3. 函数stat_vec返回sma_vecwma_vec输出在1维向量

  4. 功能stat_mat通过循环在2维向量的行(C型的行返回的sma_vecwma_vec输出)

  5. 功能stat_choose检查它是否是1维np.ndarray维或2维np.ndarray,并相应地重新导向的结果要么stat_vecstat_mat

  6. 函数smawma旨在用于stat_choose的python包装。

的安装文件如下:

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 
) 

并行的stat_mat功能,在那里我有一个循环,我做到以下几点:

  1. 在顶部,我加:

from cython.parallel import prange

  • 改变stat_mat代码(变更rangeprange):

    代替range(0, x.shape[0]),我使用prange(x.shape[0], nogil=True)

  • 在设置文件,我添加-fopenmpext_modules

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

    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 
    

    我怎样才能把这段代码转换编译它使得stat_mat并行化?

    回答

    0

    尝试改变

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

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

    Unfortenly我将无法测试,直到明天。

    +0

    我该怎么做? – uday

    +0

    我的歉意我改变了我的答案。你在做什么对我来说看起来是正确的。我明天可以尝试一些测试。但我已经改变了我的答案在一个非常简单的解决方案,你可能想尝试(但我不能检查,看看它的工作原理)。 –

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

    对于Baum的麻省理工学院眼球:使用函数指针nogil功能时nogil限定符必须是函数指针类型的一部分。在prange块中只能调用nogil函数。但是,当函数指针类型不包含nogil限定符时,在橙色或nogil块内调用是非法的。

    +0

    请解释OP的代码有什么问题,以及为什么通过编辑你的答案*解决了问题*。 –