2017-10-02 4 views
0

저는 Cython에 매우 익숙하며 Cython 문서를 건너 뛴 후에 cython을 보았습니다 확장 유형. 일반적인 Python 클래스보다 어떤 이점이 있는지 궁금합니다. 이전 파이썬 클래스를 데이터 멤버의 목록을 cython 확장 형식으로 변환하려고했지만 확장 형식의 데이터 멤버로리스트를 선언 할 수없는 것처럼 보입니다. 내가 할 수있는 유일한 것은 원시 C 데이터 유형의 데이터 멤버를 사용하는 파이썬 클래스를 cython 확장 유형으로 변환하는 것입니다.Cython 확장 유형과 파이썬 클래스 사용의 이점 이해

나는 파이썬 클래스로 파이썬 클래스를 사용하여 파이썬을 사용하여 최적화 할 필요가있다. 클래스를 cython 확장 형식으로 선언하지 않고 해당 세그먼트와 관련된 함수를 어떻게 cythonize 할 수 있습니까? (기본적으로 모든 함수가 아닌 cdef로만 선언하고 싶습니다.)

답변

2

Cython에서 코드를 작성할 때 cdef ed 클래스를 사용하지 않았으므로 다른 사람들을 위해 cdef에 대한 유형을 남겨 두겠습니다. 대답.

목록에서, 파이썬 목록을 정상적으로 사용할 수 있지만 C로 작성하는 속도 향상을 최대한 활용하려면 copy each member explicitly into a C array이 필요합니다. 그러나 데이터가 NumPy 배열 , 당신은 단지 배열의 시작 부분에 포인터를 저장할 수 있습니다 (배열이 C 연속적인지 확인하십시오). https://github.com/cython/cython/blob/master/Cython/Includes/numpy/__init__.pxd

cythonising 클래스 메서드는 대부분의 Python 코드가 Cython에서 수정없이 그대로 작동 할 수 있으므로 보통으로 class SomeClass:을 사용하여 Cython에서 클래스를 정의 할 수 있습니다. cdef 함수는 Cython 내에서만 호출 할 수 있으므로 외부의 클래스 (성능 향상을 위해 입력하는 것이 좋음)를 정의해야 할 수 있습니다. 수업 내에서 보통 def (파이썬에서 호출 할 수 있음)을 사용하여 파이썬 화 된 상대방에게 전화 할 수 있습니다.

Cython으로 옮기고 싶지 않은 대부분의 Python 클래스의 경우 비슷한 방법을 사용할 수 있지만 cdef ed 버전을 호출하는 Cython의 def ed 함수 만 사용할 수 있습니다. 그런 다음 모듈을 가져올 때 일반적으로하는 것처럼 Python에서 Cython 함수를 호출합니다.

C에 있어야하며 Python과 상호 작용하지 않아야하는 데이터 구조의 경우 PyCapsule을 사용하여 클래스 속성으로 저장하는 것이 좋습니다.

편집 :

chrisb의 대답은 아래 설명을 읽고 나면, 당신이 변수 행 길이의 2 차원 배열을하려는 수집합니다. C에서 똑같은 데이터 구조를 구현하기 전에 C가 파이썬이 아니라는 사실에 주목할 가치가 있습니다. 목록 길이를 자동으로 관리하지는 않으므로 직접 관리해야합니다 (첫 번째 링크의 예 참조). 이것이 동적으로 메모리를 할당하는 표준 방법이지만 C (및 Cython)를 처음 접하는 프로그래머는 포인터가 돌아 다니기 때문에 "malloc 및 친구들"을 만지려하지 않는 경향이 있습니다. 그 중 C 배열은 일반적으로 혼합 된 데이터 유형을 가지고 있지 않습니다. 동일한 배열에 숫자와 문자열을 둘 다 가질 수는 없습니다 (이 실제로 일 필요가있는 경우,이를 수행하는 방법이 있습니다).

이와 관련하여 데이터 구조를 다시 생각해 볼 수 있습니다. 예를 들어, 길이가 일정한 배열로 데이터를 표현하는 방법을 고려할 수 있습니다.배열의 너비가 최대 인 경우 NumPy 배열을 사용하여 쉽게 프로그래밍 할 수있는 메모리를 교환 할 수 있습니다. 수동 메모리 관리 갈 줄 행복 경우

가 여기 int s의 2 차원 배열에 대한 메모리를 할당의 간단한 예입니다 :

from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free 

cdef int **generate_2D_array(int rows, int columns): 
    cdef int row 
    cdef int **parent = <int **>PyMem_Malloc(rows * sizeof(int*)) 
    if not parent: 
     raise MemoryError() 
    for row in range(rows): 
     parent[row] = <int *>PyMem_Malloc(columns * sizeof(int)) 
     if not parent[row]: 
      raise MemoryError() 
    return parent 

은 행의 길이를 변경하려면, 당신은 사용할 수 있습니다 : 당신이 데이터를 완료하면

cdef void resize_row(int *row_pointer, int new_size): 
    PyMem_Realloc(row_pointer, new_size) 

, PyMem_Malloc으로 할당에 비슷한 방식으로 PyMem_Free을 사용하여 메모리 할당을 해제해야합니다. 엄지 손가락의 규칙은 다음과 같습니다. PyMem_Malloc을 사용할 때마다 정확히 하나만 사용하여 메모리를 해제하십시오. PyMem_Free, 더 이상 없습니다. 마지막으로, 경고의 한마디로, 적절하게 사용하지 않으면 세그멘테이션 오류, 메모리 누출 또는 정의되지 않은 동작이 발생할 수 있습니다.

0

python-heavy 연산의 경우 cdef 클래스는 최적화 된 필드 액세스와 파이썬 오버 헤드 제거로 인해 성능상의 이점을 갖습니다. 간단한 예 :

class PyThing: 
    def __init__(self, data): 
     self.data = data 
    def calc(self): 
     ans = 0 
     for v in self.data: 
      ans += v 
     return ans 


py = PyThing(list(range(100000))) 

%timeit py.calc() 
4.07 ms ± 29.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) 


import cython 
%load_ext cython 

%%cython 
cdef class CyThing: 
    cdef list data 
    def __init__(self, data): 
     self.data = data 
    def calc(self): 
     ans = 0 
     for v in self.data: 
      ans += v 
     return ans 

cy = CyThing(list(range(100000))) 

%timeit cy.calc() 
2.8 ms ± 123 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) 

이것은 단순성/디버그 기능을 희생 시키므로 그럴 가치가 있거나 없을 수도 있습니다. 더 나은 사용법은 당신이 저장하고 사용하기 원하는 C- 레벨 값을 가지고있을 때, 성능 이점이 훨씬 더 중요 할 수 있다는 것입니다.

+0

안녕하세요! 답변 해주셔서 감사합니다! 그러나 나는 우리가 cython에서도리스트를 사용할 수 있다는 것을 몰랐다! 파이썬리스트와 비교할 때 성능이 더 좋습니까? 그로 인해 성능이 향상됩니까? 또한 이러한 2D 목록을 cython으로 선언 할 수 있습니까? –

+1

예,'list'는 cython에서 사용할 수 있습니다. 파이썬 목록과 완전히 똑같은 객체입니다. 그러나 더 특수화 된 코드를 생성하고 파이썬 인터프리터 오버 헤드를 건너 뛰는 것으로 cython은 다소 빨라질 것입니다. – chrisb

+0

데이터의 유형/모양을 알고 있다면 @Capow에서 제안한 것처럼 2 차원으로 선언 할 수있는 숫자가있는 배열을 사용하는 것이 훨씬 나을 것입니다. 파이썬 목록은 (단순히 목록의 중첩 목록이 될 수 없습니다) – chrisb