一些标准的 C 库数学运算与 noGIL 不兼容

Some standard C library math operations don't play nice with noGIL

我有一个包含以下代码的 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. 为什么 libc.math abs 函数不能很好地与 nogil 一起使用,而 sqrt、pow 等其他函数似乎可以?
  2. 我必须向我的函数(和 .pxd 文件)添加什么才能使其成为 nog​​il?我已经尝试添加以下页面 https://lbolla.info/python-threads-cython-gil 但它仍然无法编译。

这个问题类似于:

提前致谢!

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

These convenience abs overloads are exclusive of C++. In C, abs is only declared in (and operates on int values).

我有点惊讶 Cython 没有抱怨你 cimporting 一些不存在的东西,但它会使用 Python abs builtin(或可能是稍微优化的 Cython 等价物)。

您需要 fabs

正如@DawidW 已经指出的那样,您应该在您的案例中使用 math.h 中的 fabs

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

  1. 这可能是一个错误:他们可以从任何地方 cimport abscythonnumpy 等等。或者根本不导入它 - 这仍然是内置 abs.
  2. Cython 尝试通过 C 对应的内置函数替换 Python 功能,整个列表 is here。根据输入的类型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)stdlib.h
  3. 翻译成 abs
  4. abs(d)math.h
  5. 翻译成 fabs

在 2. 和 3.gil 的情况下不需要,但是从 Cython 的角度来看 Python-abs 正在使用中(即使它被映射到不同的函数)这不是定义为 "nogil",因此需要 gil。

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

%%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。


对您的代码有些不相关的评论:

一个。定义 cdef double my_abs(double a) nogil 以便能够将其用作 nogil-section。

乙。我不确定,当您将 python-object 作为 varargin 传递时,Cython 是否正确理解所有内容,因为它应该如何推断 Python-object 应该被强制转换为的正确类型?最好通过显式转换来帮助它,例如:

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