Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

[Python Korea Seminar] 하늘과 바람과 별과 (Python과) C

[Python Korea Seminar] 하늘과 바람과 별과 (Python과) C

Python C 확장 모듈을 제작하는 방법들(C API, ctypes, Cython, CFFI) 소개와 간단한 장단점 비교.

Joongi Kim

May 18, 2013
Tweet

More Decks by Joongi Kim

Other Decks in Programming

Transcript

  1. / 20 자기 소개  KAIST 전산학과 박사과정 2년차 

    Microsoft Research Cambridge@UK 인턴  NexR 인턴/프리랜서  TNF Needlworks ­– 태터툴즈/텍스트큐브 개발  Team Popong ­– 국회 의안 크롤러,
  2. / 20 현재 하는 연구(=삽질)  GPU를 이용한 고속 network

    packet 처리 시스템 개발  일반 PC나 x86 서버 같은 general-purpose 플랫폼과 Linux 를 이용한 상용 라우터에 버금가는 성능의 framework  이때 고속 연산을 위해 GPU를 활용  다루는 기술  C/C++ on Linux kernel + user space  NVIDIA CUDA  and Python! 4
  3. / 20 Python을 쓰는 이유  Python으로 Django, Flask 프로그래밍도

    좀 해봤습니다.  하지만 연구에서 쓰는 가장 큰 이유는 scripting!  Python으로 하는 일  시스템 부팅 후 X 환경 없이 GPU 초기화  Custom NIC driver의 IRQ 설정  실험 조건 별로 한번에 수십 ~ 수백 번 반복 실행  각 실험마다 CPU 코어별 점유율, throughput 등 기록  실험 후 summary 및 graph 작성 5
  4. / 20 Python에서 C 사용하기  보통 속도에 민감한 알고리즘

    구현이나, C로만 제공되는 라이브러리를 사용하기 위해 사용한다.  방법 0: Python C API로 직접 import 가능한 C 모듈 짜기  방법 1: ctypes로 C 라이브러리 직접 호출하기  방법 2: Cython ­– Python처럼 쓴 코드를 C로 번역해서 import 가능한 C 모듈로 만들어준다.  방법 3: CFFI로 Python 안에서 C 코드 직접 쓰기 6
  5. / 20 Python C API  http://docs.python.org/3/c-api/  장점 

    Python 코드 실행보다 Python C API 사용한 C 코드가 빠르다. (Cython의 motivation)  단점  Python 버전 바뀌면 컴파일도 다시 해야 함. (특히 윈도용으로 배포하기 귀찮다)  Reference counting 지옥  명시적으로 해야 하는 경우 vs. 특정 API가 자동으로 하는 경우 7 C API ctypes Cython CFFI 결론
  6. / 20 Python C API example  Python 공식 문서의

    예제  직접 찾아보세요!  NumPy의 C API와 함께하는 예제  C API로 짠 importable 모듈 코드 https://github.com/achimnol/pykorea-cext- examples/blob/master/chi2-capi/_chi2.c  사용하는 순수 Python 코드 https://github.com/achimnol/pykorea-cext- examples/blob/master/chi2-capi/test.py 8 C API ctypes Cython CFFI 결론
  7. / 20 ctypes  http://docs.python.org/3/library/ctypes.html  장점  표준라이브러리! 컴파일

    필요 없다!  Python 버전에 따른 코드 변경 필요 없고, portable하다.  시스템에 library 존재 여부를 런타임에 검사 가능.  단점  C 함수를 자주 많이 부를수록 성능 오버헤드가 크다.  복잡한 구조체, 많은 수의 상수(#define
  8. / 20 ctypes example (1)  CUDA 런타임 불러서 GPU

    개수 검사 및 관련 초기화  count를 포인터로 넘기기 위해 ctypes.byref 사용  참고 : https://gist.github.com/achimnol/3404967 10 import ctypes, ctypes.util def set_gpu_affinity(): … cuda = ctypes.CDLL(ctypes.util.find_library('cudart')) count = ctypes.c_int(0) … ret = cuda.cudaGetDeviceCount(ctypes.byref(count)) assert ret == 0, 'cudaGetDeviceCount() has failed.' logger.info('Grabbed a CUDA context.') … C API ctypes Cython CFFI 결론
  9. / 20 ctypes example (2) 11 from ctypes import CDLL,

    Structure, c_char, c_int, c_byte, byref from ctypes.util import find_library class Device(Structure): _fields_ = [ ('name', c_char * 16), ('dev_addr', c_char * 6), ('ip_addr', c_byte * 4), ('ifindex', c_int), ('kifindex', c_int), ('numa_node', c_int), ('num_rx_queues', c_int), ('num_tx_queues', c_int), ] if __name__ == '__main__': libpsio = CDLL(find_library('psio')) AllDevices = Device * 64 # pre-allocated array of struct devices = AllDevices() num_devices = libpsio.ps_list_devices(byref(devices)) print('Detected devices: {}'.format( ', '.join(map(lambda dev: '{}@{}'.format(dev.name.decode('ascii'), dev.numa_node), devices[:num_devices])) )) struct ps_device { char name[IFNAMSIZ]; char dev_addr[ETH_ALEN]; uint32_t ip_addr; int ifindex; int kifindex; int numa_node; int num_rx_queues; int num_tx_queues; }; C API ctypes Cython CFFI 결론
  10. / 20 ctypes example (3)  아까 보았던 C API

    + NumPy example의 ctypes 버전  https://github.com/achimnol/pykorea-cext- examples/blob/master/chi2-ctypes/test.py  훨씬 간단!  생각해볼 점  C 함수를 반복 호출하는 경우 또는 많은 양의 데이터로 for loop를 돌리는 경우 해당 부분은 C 코드로 짜는 것이 좋다. 즉,
  11. / 20 Cython  http://www.cython.org/  장점  Python 유사

    문법으로 C 코드를 쓸 수 있다. 간결하다. (cdef
  12. / 20 Cython example  아까 보았던 C API +

    NumPy example의 Cython 버전  Cython interfacing (.pyx) https://github.com/achimnol/pykorea-cext- examples/blob/master/chi2-cython/chi2.pyx  Cython 코드(.pyx)의 C 코드 번역 결과 (!!) https://github.com/achimnol/pykorea-cext- examples/blob/master/chi2- cython/example_chi2_generated.c  사용하는 순수 Python 코드 https://github.com/achimnol/pykorea-cext- examples/blob/master/chi2-cython/test.py  사람이 작성하는 코드는 가장 간단하다! 14 wrapper.pyx native.c .so (Python importable) Cython translates to .c Compile into C module C API ctypes Cython CFFI 결론
  13. / 20 CFFI (C Foreign Function Interface)  https://bitbucket.org/cffi/cffi 

    장점  C 선언문을 그대로 쓰므로 가장 직관적이다.  ctypes처럼, 별도의 컴파일 과정이 필요 없다.  ABI (app. binary interface)와 API (app. programming interface) 모델을 둘 다 지원한다.  단점  제품용으로 쓰기엔 아직 충분히 성숙하지 않았다.  문서화가 덜 되어 있다. 15 C API ctypes Cython CFFI 결론
  14. / 20 CFFI example  아까 보았던 C API +

    NumPy example의 CFFI 버전  https://github.com/achimnol/pykorea-cext- examples/blob/master/chi2-cffi/test.py  ctypes의 장점을 가지면서도 C 선언을 그대로 사용할 수 있 어서 훨씬 직관적이다. 16 C API ctypes Cython CFFI 결론
  15. / 20 성능은 어떨까? 방법 수행 시간 (단위 : sec)

    C API 0.391 ctypes 0.450 Cython 0.403 CFFI 0.485 17  성능 좋은 순서: C API > Cython > ctypes > CFFI 실험 조건: • input random 생성과 API 호출을 함께 1000회 반복 • 각 방법 별로 4회씩 실행하여 뒤 3회의 user time 평균 (첫번째는 cache warm-up 용도) C API ctypes Cython CFFI 결론
  16. / 20 장단점 요약 방법 표준 여부 Portability 모듈 개발자의

    Cost 모듈 사용자의 Cost C API Yes 낮음 매우 높음 없음 ctypes Yes 높음 없음 중간 Cython No 높음 중간 없음 CFFI No 높음 없음 낮음 18 C API ctypes Cython CFFI 결론
  17. / 20 정리  Python에서 C 코드를 부르고 싶다면: 

    현재 가장 추천할 수 있는 방법은 ctypes! (표준 + portable)  C 함수 호출 성능이 중요하다면 Cython 권장.  CFFI는 미래의 기대주, 아직 실제로 쓰기엔…⋯  여기서 다루지 못한 내용  SWIG (Simplified Wrapper & Interface Generator)  interface 정의 1개로 여러 언어(Tcl, Python, Perl, Java 등등) 의 importable module을 컴파일할 수 있다.  Python의 경우 C API를 사용한 것과 같은 효과 19 C API ctypes Cython CFFI 결론