某些标准C库数学运算无法与noGIL配合使用

时间:2018-07-26 18:18:00

标签: cython gil

我有一个pyx文件,其中包含以下代码:

cimport cython
from libc.math cimport sqrt, abs
from libc.stdio cimport printf
from cython.parallel import prange

cdef double my_abs(double a):
    return sqrt(a*a)

cpdef loop(int a):
    cdef int i
    cdef int sum = 0
    for i in prange(a, nogil=True):
        printf("%s %i %s %f\n", "The square root of ", i, " is ", sqrt(i))
        #printf("%s %i %s %f\n", "The absolute value of ", i, " is ", abs(i))
        #printf("%s %i %s %f\n", "The absolute value of ", i, " is ", my_abs(i))
    return

当我取消注释循环中的两行中的任何一行时,哪个编译失败。

  1. 为什么在使用sqrt,pow等其他工具时,libc.math abs函数不能与nogil配合使用?
  2. 我必须添加什么功能(和.pxd文件)以使其成为nogil?我尝试在此页面https://lbolla.info/python-threads-cython-gil之后添加内容,但仍无法编译。

这个问题类似于:

谢谢!

2 个答案:

答案 0 :(得分:3)

abs isn't in the C standard library math.h

  

这些方便的Abs重载是C ++独有的。在C语言中,abs仅在中声明(并在int值上操作)。

对于Cython没有抱怨您cimport不存在的东西,我感到有些惊讶,但是它将使用Python abs builtin(或者可能是经过稍微优化的Cython等效项) )。

您要使用fabs

答案 1 :(得分:1)

@DawidW已经指出,在这种情况下,您应该使用fabs中的math.h

我想详细说明原因(据我了解):

  1. 这可能是一个错误:他们可以cimportabs等任何地方cython numpy。还是根本不导入它-保留在内置abs中。
  2. Cython尝试通过C-counterparts替换内置功能(整个列表is here)的Python功能。根据输入的类型,使用Python-{abs,C-absfabsfabsf等。

例如:

%%cython 
from numpy cimport abs  # just for fun, "cimport" abs from numpy!     
cdef do_abs(object o, int i, double d):
    print(abs(o))  
    print(abs(i))
    print(abs(d))

在这里,自动:

  1. abs(o)转换为__Pyx_PyNumber_Absolute(Python的功能)
  2. abs(i)abs转换为stdlib.h
  3. abs(d)fabs转换为math.h

在2.和3.情况下,不需要gil,但是从Cython的角度来看,正在使用Python-abs(即使将其映射到不同的函数)也没有定义为“ nogil”,因此需要gil。

如果我们真的从abs导入clib.stdlib,会发生什么?

%%cython 
from libc.stdlib cimport abs
cdef do_abs(object o, int i, double d):
    print(abs(o))
    print(abs(i))
    print(abs(d))

我们得到:

  1. Cython尝试将o强制转换为C整数(在运行时可能会失败),并对其结果调用C-abs
  2. 使用C-abs表示整数i
  3. 不会编译,因为Cython阻止将double值用作整数(这是一件好事,由于C编译器只是将双精度值转换为整数,因此花费了很多调试时间整数(如果幸运的话,发出警告)。

主要区别:现在,将abs用作整数参数可以使用nogil。


对您的代码有些不相关的注释:

A。定义cdef double my_abs(double a) nogil使其能够使用nogil节。

B。我不确定,当您将python对象作为varargin传递时,Cython可以正确理解所有内容,因为它应如何推断出将Python对象强制转换为的正确类型?最好通过显式强制转换来帮助它,例如:

printf("%d %s", abs(i), <char *>"\n")