ABOUT ME

-

Total
-
  • Python에서 C/C++언어 함수 실행하기
    컴퓨터/파이썬 2020. 10. 21. 16:06
    728x90
    반응형

    Ctypes

     

    ctypes — 파이썬용 외부 함수 라이브러리 — Python 3.9.0 문서

    ctypes — 파이썬용 외부 함수 라이브러리 ctypes

    docs.python.org

     

    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에서 불러오는 글은 아래 참고

     

    C언어: url HTML 가져오기 (C에서 Python 사용하기)

    libcurl libcurl - the multiprotocol file transfer library libcurl - the multiprotocol file transfer library libcurl is a free and easy-to-use client-side URL transfer library, supporting DICT, FILE,..

    choiseokwon.tistory.com

     


    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

     

    ctypes — 파이썬용 외부 함수 라이브러리 — Python 3.9.0 문서

    ctypes — 파이썬용 외부 함수 라이브러리 ctypes는 파이썬용 외부 함수(foreign function) 라이브러리입니다. C 호환 데이터형을 제공하며, DLL 또는 공유 라이브러리에 있는 함수를 호출할 수 있습니다.

    docs.python.org

     

    728x90

    댓글