我如何从Numba jitted类中调用Cython扩展类型的方法?下面我的最小示例失败,我在下面记录了错误。我如何修改我的最小例子以使其有效?
感谢您的帮助!!
我有一个Cython模块,shrubbery.pyx
:
cdef class Shrubbery:
cdef int height
def __init__(self, h):
self.height = h
def describe(self):
print('This shrubbery is', self.height, 'tall.')
我有一个设置文件setup.py
:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension('shrubbery', ['shrubbery.pyx'])]
setup(
name='shrubbery',
cmdclass={'build_ext': build_ext},
ext_modules=ext_modules)
我像往常一样将shrubbery.pyx
编译成扩展类型(python setup.py build_ext --inplace
)。然后我尝试在numba jitted类中使用Shrubbery
,如下所示:
from shrubbery import Shrubbery
import numba as nb
spec = [('value', nb.int32)]
@nb.jitclass(spec)
class Bag(object):
def __init__(self, value):
self.value = value
def size(self):
return self.value
def mixed_class_method(self):
__shrubbery = Shrubbery(5)
__shrubbery.describe()
# pure numba class: works
_b = Bag(value=3)
print(_b.size())
# pure cython extension type: works
__shrubbery = Shrubbery(5)
__shrubbery.describe()
# mix of cython extension type and numba jitted class: fails
_b.mixed_class_method()
/Users/mg/anaconda/bin/python3 test.py
3
('This shrubbery is', 5, 'tall.')
Traceback (most recent call last):
File "test.py", line 28, in <module>
_b.mixed_class_method()
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/jitclass/boxing.py", line 62, in wrapper
return method(*args, **kwargs)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/dispatcher.py", line 330, in _compile_for_args
raise e
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/dispatcher.py", line 307, in _compile_for_args
return self.compile(tuple(argtypes))
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/dispatcher.py", line 579, in compile
cres = self._compiler.compile(args, return_type)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/dispatcher.py", line 80, in compile
flags=flags, locals=self.locals)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 779, in compile_extra
return pipeline.compile_extra(func)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 362, in compile_extra
return self._compile_bytecode()
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 738, in _compile_bytecode
return self._compile_core()
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 725, in _compile_core
res = pm.run(self.status)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 248, in run
raise patched_exception
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 240, in run
stage()
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 454, in stage_nopython_frontend
self.locals)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 881, in type_inference_stage
infer.propagate()
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/typeinfer.py", line 846, in propagate
raise errors[0]
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/typeinfer.py", line 137, in propagate
constraint(typeinfer)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/typeinfer.py", line 415, in __call__
self.resolve(typeinfer, typevars, fnty)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/typeinfer.py", line 441, in resolve
sig = typeinfer.resolve_call(fnty, pos_args, kw_args, literals=literals)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/typeinfer.py", line 1115, in resolve_call
literals=literals)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/typing/context.py", line 204, in resolve_function_type
return func.get_call_type_with_literals(self, args, kws, literals)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/types/functions.py", line 199, in get_call_type_with_literals
return self.get_call_type(context, args, kws)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/types/functions.py", line 193, in get_call_type
return self.template(context).apply(args, kws)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/typing/templates.py", line 207, in apply
sig = generic(args, kws)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/jitclass/base.py", line 322, in generic
sig = disp_type.get_call_type(self.context, args, kws)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/types/functions.py", line 250, in get_call_type
template, pysig, args, kws = self.dispatcher.get_call_template(args, kws)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/dispatcher.py", line 269, in get_call_template
self.compile(tuple(args))
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/dispatcher.py", line 579, in compile
cres = self._compiler.compile(args, return_type)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/dispatcher.py", line 80, in compile
flags=flags, locals=self.locals)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 779, in compile_extra
return pipeline.compile_extra(func)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 362, in compile_extra
return self._compile_bytecode()
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 738, in _compile_bytecode
return self._compile_core()
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 725, in _compile_core
res = pm.run(self.status)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 248, in run
raise patched_exception
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 240, in run
stage()
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 454, in stage_nopython_frontend
self.locals)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/compiler.py", line 880, in type_inference_stage
infer.build_constraint()
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/typeinfer.py", line 802, in build_constraint
self.constrain_statement(inst)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/typeinfer.py", line 961, in constrain_statement
self.typeof_assign(inst)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/typeinfer.py", line 1023, in typeof_assign
self.typeof_global(inst, inst.target, value)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/typeinfer.py", line 1119, in typeof_global
typ = self.resolve_value_type(inst, gvar.value)
File "/Users/mg/anaconda/lib/python3.6/site-packages/numba/typeinfer.py", line 1042, in resolve_value_type
raise TypingError(msg, loc=inst.loc)
numba.errors.TypingError: Failed at nopython (nopython frontend)
Failed at nopython (nopython frontend)
Untyped global name 'Shrubbery': cannot determine Numba type of <class 'type'>
File "test.py", line 16
[1] During: resolving callee type: BoundFunction((<class 'numba.types.misc.ClassInstanceType'>, 'mixed_class_method') for instance.jitclass.Bag#7fef29835df8<value:int32>)
[2] During: typing of call at <string> (3)
答案 0 :(得分:1)
这主要是对CFFI功能可以起作用的评论中的建议的回应。这是事实,但非常限制。
您可以通过C函数指针将Cython cdef
函数转换为CFFI函数。此转换必须在Cython中进行。为了在nopython
模式下使用Numba,cdef
函数不能接受或返回Python对象。这意味着您无法进行Shrubbery
课程。只接受/返回C类型的简单函数将起作用
from libc.stdint cimport uintptr_t
cdef void f(int x) nogil:
with gil:
print(x+1)
ctypedef void (*void_int_func_pointer)(int)
def get_cffi_f():
cdef void_int_func_pointer f_ptr = f
cdef uintptr_t f_ptr_int = <uintptr_t>f_ptr
from cffi import FFI
ffi = FFI()
return ffi.cast('void (*)(int)',f_ptr_int)
在Python中,您调用call get_cffi_f()
来获取f
的CFFI包装以传递给Numba函数。请注意,我已将该功能声明为nogil
并在其中捕获了GIL - 我不能100%确定Numba是否会释放GIL,所以我这样做是为了安全。可能没有必要。
然后,您可以将这些CFFI包装传递给Numba或将它们作为全局变量访问:
import numba as nb
from cy import get_cffi_f
func_global = get_cffi_f()
@nb.jit(nopython=True)
def simple_func(func):
func(5)
func_global(6)
func(7)
@nb.jitclass([('value', nb.int32)])
class Bag(object):
def __init__(self,value):
self.value = value
def mixed_class_method(self,func):
func(self.value)
func_global(self.value-1)
simple_func(get_cffi_f())
Bag(3).mixed_class_method(get_cffi_f())
我的观点是,尝试在这里制作类似Cython类的东西是一个失败的原因。
可能有其他方法可以实现相同的目标 - 您可以让Cython使用api
或public
生成标题,并将这些标题与CFFI结合使用。
答案 1 :(得分:0)
来自numba docs:
“jitclass的所有方法都被编译成nopython函数.jitclass实例的数据在堆上被分配为C兼容的结构,这样任何编译的函数都可以绕过解释器直接访问底层数据。 “
正如DavidW所指出的,Shrubbery是一种Python类型而不是C类型,所以你不能在jitclass中使用。
你可以点击各个方法。