2017-10-25 4 views
1

나는 Cython에서 일하고있다. 어떻게 파이썬 클래스 인스턴스의 C 배열을 선언하고 배열을 파이썬 함수에 넘겨서 처리 할 수 ​​있습니까? 파이썬 클래스의파이썬 함수 내에서 파이썬 클래스와 C 배열

cdef int n=100 
class particle: 
    def __init__(self): 
     self.x=uniform(1,99) 
     self.y=uniform(1,99) 
     self.pot=0 
cdef particle parlist[n] 
def CalPot(parlist[]): 
    for i in range(N-1): 
     pot=0 
     for j in range(i,N): 
      dx=parlist[j].x-parlist[i].x 
      dy=parlist[j].y-parlist[j].y 
      r2=dx**2+dy**2 
      pot=pot+4*ep*r2*((sig/r2)**12 - (sig/r2)**6) 
     parlist[i].pot=pot 
+0

매우 비슷한 질문 : https://stackoverflow.com/questions/33851333/cython-how-do- 당신은 cdef 클래스의 배열을 만듭니다. 대답은 여전히 ​​"당신은하지 않습니다"입니다. – DavidW

답변

0

인스턴스는 파이썬 객체, 그리고 더 나은 (그들은 C 유형이 아니며, 나는 사이 썬 소스에서 그들을 위해 C 표현의 형태를 만들기위한 어떤 이유가 표시되지 않습니다) 파이썬으로 처리. 또한 nparlist과 같은 전역 변수를 사용하는 것이 좋습니다 (이 예제에서는 필요하지 않음).

class particle: 
    def __init__(self): 
     self.x = uniform(1, 99) 
     self.y = uniform(1, 99) 
     self.pot = 0 


def CalPot(parlist): 
    N = len(parlist) 
    for i in range(N): 
     pot = 0 
     for j in range(i, N): 
      dx = parlist[j].x - parlist[i].x 
      dy = parlist[j].y - parlist[j].y 
      r2 = dx**2 + dy**2 
      pot = pot + 4 * ep * r2 * ((sig/r2)**12 - (sig/r2)**6) 
     parlist[i].pot = pot 

그래서이 Cython 코드는 순수한 파이썬이됩니다.

0

Ioannis와 DavidW가 말했듯이, 파이썬 개체의 c- 배열을 생성해서는 안되며 파이썬 목록을 대신 사용해야합니다.

순수 파이썬을 Cytonizing하면 Cython이 인터프리터 부분을 잘라 내기 때문에 약 2 배의 속도가 향상됩니다. 그러나 레퍼런스 카운팅과 다이나믹 디스패치도 없으면 훨씬 더 많은 잠재력이 있습니다. 100 배까지의 속도 향상이 일반적입니다. 얼마 전에 나는 이것을 보여주는 a question이라고 대답했다.

속도를 높이려면 어떻게해야합니까? 파이썬 곱셈을 "베어 메탈 (bare metal)"곱셈으로 대체해야합니다.

첫 번째 단계 : A (파이썬)를 사용하지 마십시오 - 클래스 particle에 대한 간단한 C-구조체를 사용 - 이상도, 이하도 아니다 - 그것은 데이터의 단순한 모음입니다 :

cdef struct particle: 
    double x 
    double y 
    double pot 

우선 혜택 : 이상 (

DEF n=2000 # known at compile time 
cdef particle parlist[n] 

배열의 초기화 후 : (다른 질문이 더 큰 프로젝트에서 할 수있는 아주 똑똑한 것인지이다)이 구조체의 글로벌 C-배열을 정의 할 수 있습니다 자세한 내용은 첨부 된 목록 참조) 우리는 calcpot -fu에서 사용할 수 있습니다. nction는 (나는 약간의 정의를 변경) :

def calcpot(): 
    cdef double pot,dX,dY 
    cdef int i,j 
    for i in range(n): 
    pot=0.0 
    for j in range(i+1, n): 
     dX=parlist[i].x-parlist[j].x 
     dY=parlist[i].y-parlist[j].y 
     pot=pot+1.0/(dX*dX+dY*dY) 
    parlist[i].pot=pot 

원래 코드의 주요 차이점 : parlist[i].x와 (주) 더 이상 느린 파이썬 객체하지만 doubles 간단하고 빠르다. 최대한의 속도 향상을 얻으려면 고려해야 할 많은 미묘한 사항이 있습니다. 즉, 실제로는 cython documentation을 읽고 다시 읽어야합니다.

그만한 가치가 있었습니까? 타이밍은 (%timeit calcpot()을 통해) 내 컴퓨터에 있습니다

        Time   Speed-up 
pure python + interpreter: 924 ms ± 14.1 ms  x1.0 
pure python + cython:  609 ms ± 6.83 ms  x1.5 
cython version:    4.1 ms ± 55.3 µs  x231.0 

낮은 자 stucts를 사용을 통해 231의 속도 UP!


리스팅 파이썬 코드 :

import random 

class particle: 
    def __init__(self): 
     self.x=random.uniform(1,99) 
     self.y=random.uniform(1,99) 
     self.pot=0 

n=2000 
parlist = [particle() for _ in range(n)] 

def calcpot(): 
    for i in range(n): 
     pot=0.0 
     for j in range(i+1, n): 
     dX=parlist[i].x-parlist[j].x 
     dY=parlist[i].y-parlist[j].y 
     pot=pot+1.0/(dX*dX+dY*dY) 
     parlist[i].pot=pot 

리스팅 사이 썬 코드 :

#call init_parlist prior to calcpot! 
cdef struct particle: 
    double x 
    double y 
    double pot 

DEF n=2000 # known at compile time 
cdef particle parlist[n] 

import random 
def init_parlist(): 
    for i in range(n): 
    parlist[i].x=random.uniform(1,99) 
    parlist[i].y=random.uniform(1,99) 
    parlist[i].pot=0.0 

def calcpot(): 
    cdef double pot,dX,dY 
    cdef int i,j 
    for i in range(n): 
    pot=0.0 
    for j in range(i+1, n): 
     dX=parlist[i].x-parlist[j].x 
     dY=parlist[i].y-parlist[j].y 
     pot=pot+1.0/(dX*dX+dY*dY) 
    parlist[i].pot=pot