如何/何时使用Cython扩展类型与Cython结构体来存储在类函数中传递的数据



我有兴趣创建一个数据结构来保存传递给不同函数的数据/信息。我们目前的做法是如下代码:

# right now we use a C-struct to hold data that is passed
# around in a separate class 'A'
cdef struct Record:
double threshold       
double improvement     
cdef class A:
cpdef py_dostuff(self):
cdef Record record

record.threshold = new_threshold
record.improvement = new_improvement

cy_dostuff(&record)
cdef void cy_dostuff(self, Record record) nogil:
do_some_computation(record.threshold, record.improvement)

这使用了一个c风格的结构体,不幸的是它不支持继承,所以如果我们想用另一个使用该结构体的"子类"的类"B"创建子类"a",它就不起作用了。我使用类的尝试没有成功。理想情况下,我将能够在不牺牲性能的情况下执行以下操作。我的想法是,应该有可能用纯Cython扩展类型替换结构,因为我只使用c级的东西,但扩展类型将使我能够子类化RecordA

# now, I would like to use a Cython extension type to hold data that is passed
# around in a separate class 'A'
cdef class Record:
cdef double threshold       
cdef double improvement     
cdef class A:
cpdef py_dostuff(self):
cdef Record record

record.threshold = new_threshold
record.improvement = new_improvement

cy_dostuff(&record)
cdef void cy_dostuff(self, Record record) nogil:
do_some_computation(record.threshold, record.improvement)
# The reason I would like to use a Cython extension type is that it can then support clean inheritance of the data structure
cdef class NewRecord(Record):
cdef double threshold       
cdef double improvement     
cdef int new_attribute
# E.g. a new subclass of 'A' would still work even if all we did was extend the logic to a "NewRecord"
cdef class B(A):
cpdef py_dostuff(self):
cdef NewRecord record

record.threshold = new_threshold
record.improvement = new_improvement
record.new_attribute = new_attribute
cy_dostuff(&record)
cdef void cy_dostuff(self, Record record) nogil:
do_some_computation(record.threshold, record.improvement, record.new_attribute)

我的问题是:

  1. 我如何用纯Python类(没有Python对象允许nogil操作)代替结构正确?
  2. 会有性能差异吗?
  3. 如果我不能,为什么不和什么是变通的传递结构,如数据结构周围?

我如何正确地替换纯Python类(没有Python对象允许nogil操作)来代替结构?

使用Cythoncdef class代替结构体没有什么特别棘手的——你可以将它们传递给nogil函数并访问它们的非objectcdef属性,而不需要GIL:

cdef class A:
cdef double threshold
cdef double improvement
def example_func(self):
with nogil:
self.threshold = do_something(self)
cdef double do_something(A a) nogil:
return a.threshold

请考虑你是否真的需要在没有GIL的情况下工作(即你正在做多线程)。很多人认为"nogil==fast";并要求nogil解决方案,主要是出于货物崇拜的原因。

注意,不能取cdef class的地址。在您的(非工作)示例中,cy_dostuff(&record)将变为cy_dostuff(record)

会有性能差异吗?

可能不多。cdef class本质上是一个结构体。在内部通过指针(而不是通过值)并在堆上分配,因此这可能会有一点不同。不过,Cython会为您处理这些细节。

如果我不能,为什么不和什么是变通的传递结构像数据结构周围?

你可以通过组合进行继承:

cdef struct Record:
double threshold       
double improvement
cdef struct NewRecord:
Record base
int new_attribute

C标准明确允许在RecordNewRecord指针之间强制转换,以支持这种确切的使用。所以如果你有一个接受Record指针的函数你可以使用f(<Record*>&my_new_record)

相关内容

  • 没有找到相关文章

最新更新