-
Python에서 C/C++언어 함수 실행하기컴퓨터/파이썬 2020. 10. 21. 16:06728x90반응형
Ctypes
1. ctypes이란
C언어로 기반으로 제작된 파이썬에서,
ctypes 으로 C 호환 데이터형을 이용, DLL 또는 공유 라이브러리(.so)에 있는 함수를 호출할 수 있게 해 준다.
2. 할 것
py 파일 안에서 C/C++ 함수를 작성해서 실행하는 것을 불가능하고,
disutils에 있는 ccompiler로는 object파일밖에 생성하고
exe파일 까진 만들 수 있으나, exe실행은 따로 해야 한다.
from distutils.ccompiler import new_compiler if __name__ == '__main__': compiler = new_compiler() compiler.compile(['main.c']) compiler.link_executable(['main.obj'], 'main') import sys sys.system(r"PATH\main.exe")
그래서 공유 라이브러리 (.so 파일)을 제작하고 ctypes로 함수를 실행하고
파이썬 함수와 속도 비교를 해볼 것이다.
(C언어로 모듈을 제작할 수 있지만, 꽤 복잡하다.)
파이썬 함수 바로 C에서 불러오는 글은 아래 참고
0. 기본 지식
0. .so 파일 불러오기
우선, ctypes으로 so 파일을 불러오고, 함수를 실행하는 방법은 아래와 같다.
(fibo 함수는 c파일에 int fibo(int n))
from ctypes import CDLL if __name__ == "__main__": cfibo = CDLL("./Python/libfibo.so") cfibo.fibo(2000000000)
1. restype, argtypes
문서 참고: docs.python.org/ko/3/library/ctypes.html
c언어 파일에 있는 bubbleSort 함수는 restype(반환 타입)은 없고,
argtypes(필수 인자 타입)는 bubbleSort(int arr[], int length)를 사용할 것이므로 [*int, int]로 지정
(인자가 하나여도 [c_int] 처럼, seq안에 있어야 한다.)
bubble = CDLL("./Python/libbubble.so") bubble.bubbleSort.restype = None bubble.bubbleSort.argtypes = [POINTER(c_int), c_int]
2. 파이썬 배열 -> C언어 배열 변환
= (c_type * 길이)(*파이썬 배열)
array = [5, 4, 3, 2, 1] array = (c_int * len(array))(*array) print(array) # <__main__.c_long_Array_10000 object at 0x000001D78F28C1C8> print(list(array)) # 배열로 보려면 # [5, 4, 3, 2, 1]
3. C/C++ 파일 -> .so 파일 변환
(c++은 g++을 이용하면 된다.)
※ 64비트는 gcc 64비트 버전을 사용해야 한다, 아니면 WinError 193 오류가 발생
gcc -shared -o so파일이름.so -fPIC C파일이름.c
1. Bubble Sort (거품 정렬)
파이썬 방식과 똑같이 작성하였다.
배열 길이를 따로 준 이유는, 배열을 넘겼을 때
C언어에서 포인터로 받으니 sizeof는 안통해서 처음부터 길이를 넘겨야 함
C언어
#define API __declspec(dllexport) API void bubbleSort(int *arr, int n) { int i; int isSorted = 0; int count = 0; while (isSorted == 0) { isSorted = 1; for (i = 0; i < n - 1 - count; i++) { if (arr[i] > arr[i + 1]) { int temp = arr[i]; // arr[i], arr[i + 1] = arr[i + 1], arr[i] arr[i] = arr[i + 1]; arr[i + 1] = temp; isSorted = 0; } } count++; } }
파이썬
def bubbleSort(array): isSorted = False counter = 0 while not isSorted: isSorted = True for i in range(len(array) - 1 - counter): if array[i] > array[i + 1]: array[i], array[i + 1] = array[i + 1], array[i] isSorted = False counter += 1 return array
테스트
from timeit import default_timer from ctypes import CDLL, c_int, POINTER if __name__ == "__main__": from bigO import bigO # 랜덤 배열 생성하려고 부름 from bigO import algorithm # 파이썬 bubbleSort 불러오기 lib = bigO() # BubbleSort test print("Bubble Sort Test") array = lib.genRandomArray(10000) array2 = array[:] # 똑같은 랜덤, 얇은 복사 bubble = CDLL("./Python/libbubble.so") bubble.bubbleSort.restype = None bubble.bubbleSort.argtypes = [POINTER(c_int), c_int] array = (c_int * len(array))(*array) start = default_timer() bubble.bubbleSort(array, len(array)) # C언어 버전 실행 # print(list(array)) 결과를 보려면 주석 해제 print(f"Took {default_timer() - start:.5f}s") start = default_timer() algorithm.bubbleSort(array2) # 파이썬 버전 실행 print(f"Took {default_timer() - start:.5f}s") # 결과 # 파이썬 Took: 10.41354초 # C언어 Took: 0.26524초
결과는 역시 파이썬은 약 10초, C언어 버전은 약 0.26초가 걸렸다.
(c언어 잘하고, 빠른 함수가 필요하면 C언어 모듈로 제작해서 쓰는 게 역시 빠르다.)
2. min(), max()
C언어
모든 배열 탐색 | O(n)
int max(int *arr, int n); int min(int *arr, int n); int max(int *arr, int n) { int i; int max_value = arr[0]; for (i = 1; i < n; i++) { if (max_value < arr[i]) { max_value = arr[i]; } } return max_value; } int min(int *arr, int n) { int i; int min_value = arr[0]; for (i = 1; i < n; i++) { if (min_value > arr[i]) { min_value = arr[i]; } } return min_value; }
파이썬은 built-in 함수, min(), max()를 이용
테스트
if __name__ == "__main__": from bigO import bigO from bigO import algorithm lib = bigO() # Min and Max test print("Min Max Test") minmax = CDLL("./Python/libm.so") minmax.min.restype = c_int # return int minmax.min.argtypes = [POINTER(c_int), c_int] # min(array, n) minmax.max.restype = c_int # return int minmax.max.argtypes = [POINTER(c_int), c_int] # max(array, n) test = lib.genRandomArray(1000000) # 백만 크기 랜덤 배열 test2 = test[:] test = (c_int * len(test))(*test) start = default_timer() minmax.min(test, len(test)) minmax.max(test, len(test)) print(f"C: {default_timer() - start:.5f}s") start = default_timer() min(test2) max(test2) print(f"Python: {default_timer() - start:.5f}s") # 결과 # Min Max Test # C: 0.00402초 # Python: 0.03532초
결과는 또 역시 파이썬은 약 0.035초, C언어 버전은 약 0.004초가 걸렸다.
참고 링크
docs.python.org/ko/3/library/ctypes.html
728x90'컴퓨터 > 파이썬' 카테고리의 다른 글
Python 모듈 C언어로 만들기 (1) 2020.10.22 Python kth Hamming number (해밍 수) (0) 2020.10.19 Python fastcore: 파이썬 업그레이드 모듈 (0) 2020.10.17