簡體   English   中英

如何/何時使用 Cython 擴展類型與 Cython 結構來存儲圍繞類函數傳遞的數據

[英]How/When to use a Cython Extension Type vs a Cython Struct to store data that is passed around class functions

我有興趣創建一個數據結構來保存傳遞給不同函數的數據/信息。 我們目前的做法是如下代碼:

# 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. 如何正確替換結構的純 Cython 類(沒有 Python 對象以允許 nogil 操作)?
  2. 會有性能差異嗎?
  3. 如果我做不到,為什么不呢?有什么解決方法可以傳遞類似結構的數據結構?

如何正確替換結構的純 Cython 類(沒有 Python 對象以允許 nogil 操作)?

使用 Cython cdef class代替結構沒有什么特別棘手的——您可以將它們傳遞給nogil函數並訪問它們的非object cdef屬性,而無需 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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM