如何在 cython 中将 prange 与 python 函数一起使用?

问题描述 投票:0回答:1

这个问题与:53641278密切相关。在该问题的评论中,@ead 建议使用问题 53619438 的 @DavidW 评论中的方法。

在我的问题中,用户向我提供了一个自定义Python函数(例如

times_two()
),我事先不知道它,我只知道参数和输出的数据类型(
int
int
)。我的工作是计算这个函数的大范围参数(例如
1000
)。为了加快速度,我想使用
prange
,它需要
C
数据类型。

我想使用上述评论中的方法,我尝试这样做:

脚本.pyx

import ctypes

ctypedef int (* FuncPtr) (int tt)
ftype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)

cdef loop_over(FuncPtr cy_f_ptr):
    cdef:
        int i, s = 0

    for i in range(1000):
        s += cy_f_ptr(i)

    return s

cpdef get_sum(func):
    cdef FuncPtr cy_f_ptr = (<FuncPtr *> <size_t> ctypes.addressof(ftype(func)))[0]
    s = loop_over(cy_f_ptr)
    return s

设置.py

from distutils.core import setup
from Cython.Build import cythonize

setup(name="script", ext_modules=cythonize("script.pyx", compiler_directives={"language_level": "3"}))

终端

python setup.py build_ext -i

主.py

from script import get_sum


def times_two(x):
    return x*2


print(get_sum(times_two))

运行时,出现以下错误:

Process finished with exit code -1073741819 (0xC0000005)

我的期望是代码将打印值

999000

cython
1个回答
0
投票

我怀疑你的代码崩溃了,因为你扔掉了一个临时的:

你变了

f = ftype(func)
cdef FuncPtr cy_f_ptr = (<FuncPtr *> <size_t> ctypes.addressof(f))[0]

cdef FuncPtr cy_f_ptr = (<FuncPtr *> <size_t> ctypes.addressof(ftype(func)))[0]

只要函数指针存在,

ftype
对象就必须保持活动状态。在我的版本中是这样,而在您的版本中,
ftype
对象几乎立即被销毁,这意味着函数指针一旦拥有它就无效。


但是,这里有一个基本问题:要调用 Python 函数,您必须持有 GIL,这意味着您不能使用

prange
来并行化它。你的函数指针方案稍微掩盖了这一点,但它仍然是正确的。

如果你在

with gil:
的调用周围引入
cy_f_ptr
,那么工作会是什么样的。仅当函数在内部释放 GIL 时,这才有意义(即最终调用优化的 C 代码本身)。
ctypes
可能会获取 GIL 本身 - 我不确定 - 但这仍然不会改变你无法像这样并行化 Python 代码的计算。

© www.soinside.com 2019 - 2024. All rights reserved.