이 문서에서는 CPython용 C++ 확장 모듈을 빌드하여 하이퍼볼릭 탄젠트를 계산하고 Python 코드에서 호출합니다. 루틴은 C++에서 동일한 루틴을 구현하는 상대적 성능 향상을 보여주기 위해 Python에서 먼저 구현됩니다.
C++(또는 C)로 작성된 코드 모듈은 일반적으로 Python 인터프리터의 기능을 확장하는 데 사용됩니다. 확장 모듈에는 다음과 같은 세 가지 기본 유형이 있습니다.
- 가속기 모듈: 가속 성능을 사용하도록 설정합니다. Python은 해석된 언어이므로 성능 향상을 위해 C++에서 액셀러레이터 모듈을 작성할 수 있습니다.
- 래퍼 모듈: 기존 C/C++ 인터페이스를 Python 코드에 노출하거나 Python에서 사용하기 쉬운 Python과 유사한 API를 노출합니다.
-
하위 수준 시스템 액세스 모듈: 시스템 액세스 모듈을 만들어 런타임, 운영 체제 또는 기본 하드웨어의
CPython
하위 수준 기능에 도달합니다.
이 문서에서는 Python에서 C++ 확장 모듈을 사용할 수 있도록 하는 두 가지 방법을 보여 줍니다.
-
CPython
에 설명된 대로 표준 확장을 사용합니다. - 단순성 때문에 C++11에 권장되는 PyBind11을 사용합니다. 호환성을 보장하려면 최신 버전의 Python 중 하나를 사용 중인지 확인합니다.
이 연습에 대해 완료된 샘플은 Python-samples-vs-cpp-extension의 GitHub에서 사용할 수 있습니다.
필수 조건
Python 개발 워크로드가 설치된 Visual Studio 2017 이상. 워크로드에는 네이티브 확장에 필요한 C++ 워크로드 및 도구 집합을 추가하는 Python 네이티브 개발 도구가 포함됩니다.
설치 옵션에 대한 자세한 내용은 Visual Studio용 Python 설치 지원을 참조하세요.
비고
데이터 과학 및 분석 애플리케이션 워크로드를 설치하면 Python 및 Python 네이티브 개발 도구 옵션이 기본적으로 설치됩니다.
Python을 별도로 설치하는 경우 Python 설치 관리자의 고급 옵션에서 디버깅 기호 다운로드를 선택해야 합니다. 이 옵션은 Python 코드와 네이티브 코드 간에 혼합 모드 디버깅을 사용하는 데 필요합니다.
Python 애플리케이션 만들기
다음 단계에 따라 Python 애플리케이션을 만듭니다.
새 파일 프로젝트를 선택하여 > Visual Studio에서새> Python프로젝트를 만듭니다.
새 프로젝트 만들기 대화 상자에서 Python을 검색합니다. Python 애플리케이션 템플릿을 선택하고 다음을 선택합니다.
프로젝트 이름 및 위치를 입력하고 만들기를 선택합니다.
Visual Studio에서 새 프로젝트를 만듭니다. 프로젝트가 솔루션 탐색기 에서 열리고 코드 편집기에서 프로젝트 파일(.py)이 열립니다.
.py 파일에 다음 코드를 붙여넣습니다. 일부 Python 편집 기능을 경험하려면 코드를 수동으로 입력해 보세요.
이 코드는 수학 라이브러리를 사용하지 않고 하이퍼볼릭 탄젠트를 계산하며, 나중에 Python 네이티브 확장을 사용하여 가속화합니다.
팁 (조언)
C++에서 다시 작성하기 전에 순수 Python으로 코드를 작성합니다. 이렇게 하면 네이티브 Python 코드가 올바른지 보다 쉽게 확인할 수 있습니다.
from random import random from time import perf_counter # Change the value of COUNT according to the speed of your computer. # The value should enable the benchmark to complete in approximately 2 seconds. COUNT = 500000 DATA = [(random() - 0.5) * 3 for _ in range(COUNT)] e = 2.7182818284590452353602874713527 def sinh(x): return (1 - (e ** (-2 * x))) / (2 * (e ** -x)) def cosh(x): return (1 + (e ** (-2 * x))) / (2 * (e ** -x)) def tanh(x): tanh_x = sinh(x) / cosh(x) return tanh_x def test(fn, name): start = perf_counter() result = fn(DATA) duration = perf_counter() - start print('{} took {:.3f} seconds\n\n'.format(name, duration)) for d in result: assert -1 <= d <= 1, " incorrect values" if __name__ == "__main__": print('Running benchmarks with COUNT = {}'.format(COUNT)) test(lambda d: [tanh(x) for x in d], '[tanh(x) for x in d] (Python implementation)')
디버깅하지 않고> 시작을 선택하여 프로그램을 실행하거나 바로 가기 키 Ctrl+F5를 선택합니다.
프로그램 출력을 표시하는 명령 창이 열립니다.
출력에서 벤치마크 프로세스에 대해 보고된 시간을 확인합니다.
이 연습에서는 벤치마크 프로세스에 약 2초가 소요됩니다.
필요에 따라 코드의
COUNT
변수 값을 조정하여 컴퓨터에서 벤치마크가 약 2초 안에 완료되도록 합니다.프로그램을 다시 실행하고 수정된
COUNT
값이 약 2초 만에 벤치마크를 생성하는지 확인합니다.
팁 (조언)
벤치마크를 실행할 때는 항상디버깅 없이> 시작 옵션을 사용합니다. 이 메서드는 Visual Studio 디버거 내에서 코드를 실행할 때 발생할 수 있는 오버헤드를 방지하는 데 도움이 됩니다.
핵심 C++ 프로젝트 만들기
다음 단계에 따라 두 개의 동일한 C++ 프로젝트인 superfastcode 및 superfastcode2를 만듭니다. 나중에 각 프로젝트에서 다른 접근 방식을 사용하여 C++ 코드를 Python에 노출합니다.
솔루션 탐색기에서 솔루션 이름을 마우스 오른쪽 단추로 클릭하고새 프로젝트>를 선택합니다.
Visual Studio 솔루션은 Python 및 C++ 프로젝트를 모두 포함할 수 있으며, 이는 Python 개발에 Visual Studio를 사용할 때의 이점 중 하나입니다.
새 프로젝트 추가 대화 상자에서 언어 필터를 C++로 설정하고 검색 상자에 빈 상태로 입력합니다.
프로젝트 템플릿 결과 목록에서 빈 프로젝트를 선택하고 다음을 선택합니다.
새 프로젝트 구성 대화 상자에서 프로젝트 이름을 입력합니다.
- 첫 번째 프로젝트의 경우 초고속 코드라는 이름을 입력합니다.
- 두 번째 프로젝트의 경우 superfastcode2라는 이름을 입력합니다.
선택하고생성합니다.
이러한 단계를 반복하고 두 개의 프로젝트를 만들어야 합니다.
팁 (조언)
Visual Studio에 Python 네이티브 개발 도구가 설치되어 있는 경우 다른 방법을 사용할 수 있습니다. 이 문서에 설명된 많은 단계를 미리 완료하는 Python 확장 모듈 템플릿으로 시작할 수 있습니다.
이 문서의 연습에서는 빈 프로젝트로 시작하여 확장 모듈을 단계별로 빌드하는 방법을 보여 줍니다. 프로세스를 이해한 후에는 대체 템플릿을 사용하여 고유한 확장을 작성할 때 시간을 절약할 수 있습니다.
프로젝트에 C++ 파일 추가
다음으로, 각 프로젝트에 C++ 파일을 추가합니다.
솔루션 탐색기에서 프로젝트를 확장하고 원본 파일 노드를 마우스 오른쪽 단추로 클릭한 다음새 항목>를 선택합니다.
파일 템플릿 목록에서 C++ 파일(.cpp)을 선택합니다.
파일의 이름을module.cpp 입력한 다음 추가를 선택합니다.
중요합니다
파일 이름에 .cpp 확장명을 포함해야 합니다. Visual Studio는 C++ 프로젝트 속성 페이지를 표시할 수 있도록 .cpp 확장이 있는 파일을 찾습니다.
도구 모음에서 구성 드롭다운 메뉴를 확장하고 대상 구성 유형을 선택합니다.
- 64비트 Python 런타임의 경우 x64 구성을 활성화합니다.
- 32비트 Python 런타임의 경우 Win32 구성을 활성화합니다.
두 프로젝트 모두에 대해 이러한 단계를 반복해야 합니다.
프로젝트 속성 구성
새 C++ 파일에 코드를 추가하기 전에 각 C++ 모듈 프로젝트에 대한 속성을 구성하고 구성을 테스트하여 모든 것이 작동하는지 확인합니다.
각 모듈의 디버그 및 릴리스 빌드 구성 모두에 대한 프로젝트 속성을 설정해야 합니다.
솔루션 탐색기에서 C++ 모듈 프로젝트(superfastcode 또는superfastcode2)를 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다.
모듈의 디버그 빌드에 대한 속성을 구성한 다음 릴리스 빌드에 대해 동일한 속성을 구성합니다.
프로젝트 속성 페이지 대화 상자의 맨 위에서 다음 파일 구성 옵션을 구성합니다.
구성에 대해 디버그 또는 릴리스를 선택합니다. ( 활성 접두사로 이러한 옵션이 표시될 수 있습니다.)
플랫폼의 경우 이전 단계에서 선택한 항목에 따라 활성(x64) 또는 활성(Win32)을 선택합니다.
비고
고유한 프로젝트를 만들 때 특정 시나리오 요구 사항에 따라 디버그 및 릴리스 구성을 별도로 구성해야 합니다. 이 연습에서는 CPython의 릴리스 빌드를 사용하도록 구성을 설정합니다. 이 구성은 어설션을 포함하여 C++ 런타임의 일부 디버깅 기능을 사용하지 않도록 설정합니다. CPython 디버그 이진 파일(python_d.exe)을 사용하려면 다른 설정이 필요합니다.
다음 표에 설명된 대로 다른 프로젝트 속성을 설정합니다.
속성 값을 변경하려면 속성 필드에 값을 입력합니다. 일부 필드의 경우 현재 값을 선택하여 선택 항목의 드롭다운 메뉴를 확장하거나 대화 상자를 열어 값을 정의할 수 있습니다.
탭에서 값을 업데이트한 후 다른 탭으로 전환하기 전에 적용 을 선택합니다. 이 작업은 변경 내용이 유지되도록 하는 데 도움이 됩니다.
탭 및 섹션 재산 가치 구성 속성>일반 대상 이름 from...import
와 같은 문에서 Python에서 참조할 모듈의 이름을 지정합니다. Python용 모듈을 정의할 때 C++ 코드에서 이 동일한 이름을 사용합니다. 프로젝트 이름을 모듈 이름으로 사용하려면 기본값 $<ProjectName을 그대로 둡니다>.python_d.exe
의 경우, 이름 끝에_d
을/를 추가하세요.구성 유형 동적 라이브러리(.dll) 구성 속성>고급 대상 파일 확장자 .pyd (Python 확장 모듈) C/C++>일반 추가 포함 디렉터리 설치에 적합한 Python include 폴더를 추가합니다(예 : c:\Python36\include). C/C++>전처리기 전처리기 정의 있는 경우 cPython의 비데버그 버전과 일치하도록 _DEBUG 값을 NDEBUG 로 변경합니다. python_d.exe사용하는 경우 이 값을 변경하지 않고 그대로 둡니다. C/C++>코드 생성 런타임 라이브러리 CPython의 릴리스(비디버그) 버전에 맞추기 위한 다중 스레드 DLL(/MD)입니다. python_d.exe사용하는 경우 이 값을 다중 스레드 디버그 DLL(/MDd)로 둡니다. 기본 런타임 검사 기본값 링커>일반 추가 라이브러리 디렉터리 설치에 적합한 .lib 파일이 포함된 Python libs 폴더를 추가합니다(예: c:\Python36\libs). libs 폴더에 .lib 파일이 포함되도록 하고, .py 파일이 포함된 Lib 폴더가 아니도록 하십시오. 중요합니다
C/C++ 탭이 프로젝트 속성에 대한 옵션으로 표시되지 않으면 Visual Studio에서 C/C++ 소스 파일로 식별하는 코드 파일이 프로젝트에 포함되지 않습니다. 이 조건은 .c 또는 .cpp 파일 확장자 없이 소스 파일을 만드는 경우에 발생할 수 있습니다.
C++ 파일을 만들 때 module.cpp 대신 module.coo를 실수로 입력한 경우 Visual Studio는 파일을 만들지만 파일 형식을 C/C+ 컴파일러로 설정하지는 않습니다. 이 파일 형식은 프로젝트 속성 대화 상자에서 C/C++ 속성 탭의 존재를 활성화하는 데 필요합니다. 코드 파일의 이름을 .cpp 파일 확장명으로 바꿔도 오인은 계속됩니다.
코드 파일 형식을 올바르게 설정하려면 솔루션 탐색기에서 코드 파일을 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다. 항목 유형에 대해 C/C++ 컴파일러를 선택합니다.
모든 속성을 업데이트한 후 확인을 선택합니다.
다른 빌드 구성에 대한 단계를 반복합니다.
현재 구성을 테스트합니다. 두 C++ 프로젝트의 디버그 및 릴리스 빌드 모두에 대해 다음 단계를 반복합니다.
코드 추가 및 테스트 구성
이제 C++ 파일에 코드를 추가하고 릴리스 빌드를 테스트할 준비가 되었습니다.
초고속 C++ 프로젝트의 경우 코드 편집기에서 module.cpp 파일을 엽니다.
module.cpp 파일에 다음 코드를 붙여넣습니다.
#include <Windows.h> #include <cmath> const double e = 2.7182818284590452353602874713527; double sinh_impl(double x) { return (1 - pow(e, (-2 * x))) / (2 * pow(e, -x)); } double cosh_impl(double x) { return (1 + pow(e, (-2 * x))) / (2 * pow(e, -x)); } double tanh_impl(double x) { return sinh_impl(x) / cosh_impl(x); }
변경 내용을 저장합니다.
C++ 프로젝트에 대한 릴리스 구성을 빌드하여 코드가 올바른지 확인합니다.
단계를 반복하여 superfastcode2 프로젝트의 C++ 파일에 코드를 추가하고 릴리스 빌드를 테스트합니다.
C++ 프로젝트를 Python 확장으로 변환
C++ DLL을 Python용 확장으로 만들려면 먼저 내보낸 메서드를 수정하여 Python 형식과 상호 작용합니다. 그런 다음 모듈의 메서드에 대한 정의와 함께 모듈을 내보내는 함수를 추가합니다.
다음 섹션에서는 CPython 확장 및 PyBind11을 사용하여 확장을 만드는 방법을 보여 줍니다. superfasctcode 프로젝트는 CPython 확장을 사용하고 superfasctcode2 프로젝트는 PyBind11을 구현합니다.
CPython 확장 사용
이 섹션에 제시된 코드에 대한 자세한 내용은 Python/C API 참조 설명서, 특히 모듈 개체 페이지를 참조하세요. 참조 콘텐츠를 검토할 때 오른쪽 위에 있는 드롭다운 목록에서 Python 버전을 선택해야 합니다.
초고속 C++ 프로젝트의 경우 코드 편집기에서 module.cpp 파일을 엽니다.
python.h 헤더 파일을 포함하도록 module.cpp 파일의 맨 위에 문을 추가합니다.
#include <Python.h>
tanh_impl
Python 형식(즉, aPyObject*
)을 수락하고 반환하도록 메서드 코드를 바꿉다.PyObject* tanh_impl(PyObject* /* unused module reference */, PyObject* o) { double x = PyFloat_AsDouble(o); double tanh_x = sinh_impl(x) / cosh_impl(x); return PyFloat_FromDouble(tanh_x); }
파일의 끝에서 C++
tanh_impl
함수를 Python에 제공하는 방법을 정의하는 구조를 추가합니다.static PyMethodDef superfastcode_methods[] = { // The first property is the name exposed to Python, fast_tanh // The second is the C++ function with the implementation // METH_O means it takes a single PyObject argument { "fast_tanh", (PyCFunction)tanh_impl, METH_O, nullptr }, // Terminate the array with an object containing nulls { nullptr, nullptr, 0, nullptr } };
Python 코드에서
from...import
문을 사용할 때 모듈을 참조하는 방법을 정의하는 또 다른 구조를 추가하세요.이 코드에서 가져온 이름은 구성 속성>일반>대상 이름 아래의 프로젝트 속성 값과 일치해야 합니다.
다음 예에서는
"superfastcode"
이름을 사용하여 Python에서from superfastcode import fast_tanh
문을 사용할 수 있다는 의미입니다. 이는fast_tanh
가superfastcode_methods
안에 정의되어 있기 때문입니다. C++ 프로젝트 내부 파일 이름(예: module.cpp)은 중요하지 않습니다.static PyModuleDef superfastcode_module = { PyModuleDef_HEAD_INIT, "superfastcode", // Module name to use with Python import statements "Provides some functions, but faster", // Module description 0, superfastcode_methods // Structure that defines the methods of the module };
Python이 모듈을 로드할 때 호출하는 메서드를 추가합니다.
PyInit_<module-name>
<.>> 즉, 메서드 이름은 프로젝트에서 빌드한 .pyd 파일의 파일 이름과 일치합니다.PyMODINIT_FUNC PyInit_superfastcode() { return PyModule_Create(&superfastcode_module); }
C++ 프로젝트를 빌드하고 코드를 확인합니다. 오류가 발생하면 "컴파일 오류 문제 해결" 섹션을 참조하세요.
PyBind11 사용
초고속 코드 프로젝트에 대한 이전 섹션의 단계를 완료하는 경우 연습에서 C++ CPython 확장에 대한 모듈 구조를 만들기 위해 상용구 코드가 필요한 것을 알 수 있습니다. 이 연습에서는 PyBind11이 코딩 프로세스를 간소화한다는 것을 알게 됩니다. C++ 헤더 파일에서 매크로를 사용하여 동일한 결과를 수행하지만 코드는 훨씬 적습니다. 그러나 Visual Studio에서 PyBind11 라이브러리를 찾고 파일을 포함할 수 있도록 추가 단계가 필요합니다. 이 섹션의 코드에 대한 자세한 내용은 PyBind11 기본 사항을 참조하세요.
PyBind11 설치
첫 번째 단계는 프로젝트 구성에 PyBind11을 설치하는 것입니다. 이 연습에서는 개발자 PowerShell 창을 사용합니다.
도구>명령줄>개발자 PowerShell 창을 엽니다.
개발자 PowerShell 창에서 pip 명령
pip install pybind11
또는py -m pip install pybind11
를 사용하여 PyBind11을 설치합니다.Visual Studio는 PyBind11 및 종속 패키지를 설치합니다.
프로젝트에 PyBind11 경로 추가
PyBind11이 설치되면 PyBind11 경로를 프로젝트의 추가 포함 디렉터리 속성에 추가해야 합니다.
Developer PowerShell 창에서
python -m pybind11 --includes
명령 또는py -m pybind11 --includes
명령을 실행하세요.이 작업은 프로젝트 속성에 추가해야 하는 PyBind11 경로 목록을 출력합니다.
창의 경로 목록을 강조 표시하고 창 도구 모음에서 복사 (두 페이지)를 선택합니다.
연결된 경로 목록이 클립보드에 추가됩니다.
솔루션 탐색기에서 superfastcode2 프로젝트를 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다.
속성 페이지 대화 상자의 맨 위에 있는 구성 필드에 대해 릴리스를 선택합니다. ( 활성 접두사로 이 옵션이 표시될 수 있습니다.)
대화 상자의 C/C++>일반 탭에서 추가 포함 디렉터리 속성의 드롭다운 메뉴를 확장하고 편집을 선택합니다.
팝업 대화 상자에서 복사한 경로 목록을 추가합니다.
개발자 PowerShell 창에서 복사한 연결된 목록의 각 경로에 대해 다음 단계를 반복합니다.
팝업 대화 상자 도구 모음에서 새 줄 (더하기 기호가 있는 폴더)을 선택합니다.
Visual Studio는 경로 목록 맨 위에 빈 줄을 추가하고 삽입 커서를 시작 부분에 배치합니다.
PyBind11 경로를 빈 줄에 붙여넣습니다.
추가 옵션(...)을 선택하고 팝업 파일 탐색기 대화 상자를 사용하여 경로 위치를 찾아볼 수도 있습니다.
중요합니다
- 경로에 접두사를 포함하는
-I
경우 경로에서 접두사를 제거합니다. - Visual Studio에서 경로를 인식하려면 경로가 별도의 줄에 있어야 합니다.
새 경로를 추가한 후 Visual Studio는 평가된 값 필드에 확인된 경로를 표시합니다.
- 경로에 접두사를 포함하는
확인을 선택하여 팝업 대화 상자를 종료합니다.
속성 페이지 대화 상자의 맨 위에서 추가 포함 디렉터리 속성의 값을 마우스로 가리키고 PyBind11 경로가 있는지 확인합니다.
확인을 선택하여 속성 변경 내용을 적용합니다.
module.cpp 파일 업데이트
마지막 단계는 PyBind11 헤더 파일 및 매크로 코드를 프로젝트 C++ 파일에 추가하는 것입니다.
superfastcode2 C++ 프로젝트의 경우 코드 편집기에서 module.cpp 파일을 엽니다.
pybind11.h 헤더 파일을 포함하도록 module.cpp 파일의 맨 위에 문을 추가합니다.
#include <pybind11/pybind11.h>
module.cpp 파일의 끝에서 매크로에 대한 코드를 추가하여 C++ 함수에 대한
PYBIND11_MODULE
진입점을 정의합니다.namespace py = pybind11; PYBIND11_MODULE(superfastcode2, m) { m.def("fast_tanh2", &tanh_impl, R"pbdoc( Compute a hyperbolic tangent of a single argument expressed in radians. )pbdoc"); #ifdef VERSION_INFO m.attr("__version__") = VERSION_INFO; #else m.attr("__version__") = "dev"; #endif }
C++ 프로젝트를 빌드하고 코드를 확인합니다. 오류가 발생하면 다음 섹션인 컴파일 오류 문제 해결을 참조하세요.
컴파일 오류 문제 해결
C++ 모듈 빌드가 실패할 수 있는 가능한 문제는 다음 섹션을 검토하세요.
오류: 헤더 파일을 찾을 수 없습니다.
Visual Studio는 E1696과 같은 오류 메시지를 반환합니다. 소스 파일 "Python.h" 또는 C1083을 열 수 없습니다. 포함 파일을 열 수 없습니다. "Python.h": 이러한 파일이나 디렉터리가 없습니다.
이 오류는 컴파일러가 프로젝트에 필요한 헤더(.h) 파일을 찾을 수 없음을 나타냅니다.
초고속 코드 프로젝트의 경우 C/C++>일반>추가 포함 디렉터리 프로젝트 속성에 Python 설치를 위한 include 폴더에 대한 경로가 포함되어 있는지 확인합니다. 프로젝트 속성 구성의 단계를 검토합니다.
superfastcode2 프로젝트의 경우 동일한 프로젝트 속성에 PyBind11 설치에 대한 include 폴더의 경로가 포함되어 있는지 확인합니다. Ad PyBind 경로를 프로젝트에 추가하는 단계 검토
Python 설치 구성 정보에 액세스하는 방법에 대한 자세한 내용은 Python 설명서를 참조하세요.
오류: Python 라이브러리를 찾을 수 없음
Visual Studio는 컴파일러가 프로젝트에 필요한 DLL(라이브러리) 파일을 찾을 수 없음을 나타내는 오류를 반환합니다.
- C++ 프로젝트(superfastcode 또는 superfastcode2)의 경우 링커>일반>추가 라이브러리 디렉터리 속성에 Python 설치를 위한 libs 폴더에 대한 경로가 포함되어 있는지 확인합니다. 프로젝트 속성 구성의 단계를 검토합니다.
Python 설치 구성 정보에 액세스하는 방법에 대한 자세한 내용은 Python 설명서를 참조하세요.
대상 아키텍처와 관련된 링커 오류
Visual Studio는 x64 또는 Win32와 같은 프로젝트의 대상 아키텍처 구성과 관련된 링커 오류를 보고합니다.
- C++ 프로젝트(superfastcode 또는 superfastcode2)의 경우 Python 설치와 일치하도록 대상 구성을 변경합니다. 예를 들어 C++ 프로젝트 대상 구성이 Win32이지만 Python 설치가 64비트인 경우 C++ 프로젝트 대상 구성을 x64로 변경합니다.
코드를 테스트하고 결과를 비교합니다.
이제 Python 확장으로 구조화된 DLL이 있으므로 Python 프로젝트에서 참조하고, 모듈을 가져오고, 해당 메서드를 사용할 수 있습니다.
Python에서 DLL을 사용할 수 있도록 만들기
여러 가지 방법으로 Python에서 DLL을 사용할 수 있도록 할 수 있습니다. 고려해야 할 두 가지 옵션은 다음과 같습니다.
Python 프로젝트와 C++ 프로젝트가 동일한 솔루션에 있는 경우 다음 방법을 사용할 수 있습니다.
솔루션 탐색기에서 Python 프로젝트에서 참조 노드를 마우스 오른쪽 단추로 클릭하고 참조 추가를 선택합니다.
C++ 프로젝트가 아닌 Python 프로젝트에 대해 이 작업을 수행해야 합니다.
참조 추가 대화 상자에서 프로젝트 탭을 확장합니다.
superfastcode 및 superfastcode2 프로젝트 모두에 대한 확인란을 선택하고 확인을 선택합니다.
다른 방법은 Python 환경에 C++ 확장 모듈을 설치하는 것입니다. 이 메서드를 사용하면 다른 Python 프로젝트에서 모듈을 사용할 수 있습니다. 자세한 내용은 setuptools 프로젝트 설명서를 참조하세요.
다음 단계를 완료하여 Python 환경에 C++ 확장 모듈을 설치합니다.
솔루션 탐색기에서 C++ 프로젝트를 마우스 오른쪽 단추로 클릭하고새 항목>를 선택합니다.
파일 템플릿 목록에서 C++ 파일(.cpp)을 선택합니다.
파일의 이름을setup.py 입력한 다음 추가를 선택합니다.
Python(.py) 확장명을 사용하여 파일 이름을 입력해야 합니다. Visual Studio는 C++ 파일 템플릿을 사용했음에도 불구하고 파일을 Python 코드로 인식합니다.
Visual Studio가 코드 편집기에서 새 파일을 엽니다.
다음 코드를 새 파일에 붙여넣습니다. 확장 메서드에 해당하는 코드 버전을 선택합니다.
CPython 확장 (superfastcode 프로젝트):
from setuptools import setup, Extension sfc_module = Extension('superfastcode', sources = ['module.cpp']) setup( name='superfastcode', version='1.0', description='Python Package with superfastcode C++ extension', ext_modules=[sfc_module] )
PyBind11 (superfastcode2 프로젝트):
from setuptools import setup, Extension import pybind11 cpp_args = ['-std=c++11', '-stdlib=libc++', '-mmacosx-version-min=10.7'] sfc_module = Extension( 'superfastcode2', sources=['module.cpp'], include_dirs=[pybind11.get_include()], language='c++', extra_compile_args=cpp_args, ) setup( name='superfastcode2', version='1.0', description='Python package with superfastcode2 C++ extension (PyBind11)', ext_modules=[sfc_module], )
C++ 프로젝트에서 pyproject.toml이라는 두 번째 파일을 만들고 다음 코드를 붙여넣습니다.
[build-system] requires = ["setuptools", "wheel", "pybind11"] build-backend = "setuptools.build_meta"
TOML(.toml) 파일은 구성 파일에 Tom의 명백한 최소 언어 형식을 사용합니다.
확장을 빌드하려면 코드 창 탭에서 pyproject.toml 파일 이름을 마우스 오른쪽 단추로 클릭하고 전체 경로 복사를 선택합니다.
사용하기 전에 경로에서 pyproject.toml 이름을 삭제합니다.
솔루션 탐색기에서 솔루션에 대한 Python 환경 노드를 확장합니다.
활성 Python 환경(굵게 표시됨)을 마우스 오른쪽 단추로 클릭하고 Python 패키지 관리를 선택합니다.
Python 환경 창이 열립니다.
필요한 패키지가 이미 설치되어 있으면 이 창에 나열됩니다.
- 계속하기 전에 패키지 이름 옆에 있는 X 를 선택하여 제거합니다.
Python 환경 검색 창의 검색 상자에 복사한 경로를 붙여넣고 경로 끝에서 pyproject.toml 파일 이름을 삭제합니다.
Enter 키를 선택하여 복사한 경로의 위치에서 모듈을 설치합니다.
팁 (조언)
권한 오류로 인해 설치가 실패하면 명령 끝에 인수를 추가하고
--user
설치를 다시 시도합니다.
Python에서 DLL 호출
이전 섹션에 설명된 대로 DLL을 Python에서 사용할 수 있게 되면, Python에서 superfastcode.fast_tanh
및 superfastcode2.fast_tanh2
함수를 호출할 준비가 된 것입니다. 그런 다음 함수 성능을 Python 구현과 비교할 수 있습니다.
다음 단계에 따라 Python에서 확장 모듈 DLL을 호출합니다.
코드 편집기에서 Python 프로젝트에 대한 .py 파일을 엽니다.
파일의 끝에 다음 코드를 추가하여 DLL에서 내보낸 메서드를 호출하고 출력을 표시합니다.
from superfastcode import fast_tanh test(lambda d: [fast_tanh(x) for x in d], '[fast_tanh(x) for x in d] (CPython C++ extension)') from superfastcode2 import fast_tanh2 test(lambda d: [fast_tanh2(x) for x in d], '[fast_tanh2(x) for x in d] (PyBind11 C++ extension)')
디버깅하지 않고> 시작을 선택하여 Python 프로그램을 실행하거나 바로 가기 키 Ctrl+F5를 사용합니다.
비고
디버깅하지 않고 시작 명령을 사용할 수 없는 경우 솔루션 탐색기에서 Python 프로젝트를 마우스 오른쪽 단추로 클릭한 다음 시작 프로젝트로 설정을 선택합니다.
프로그램이 실행되면 C++ 루틴이 Python 구현보다 약 5~20배 빠르게 실행됩니다.
일반적인 프로그램 출력의 예는 다음과 같습니다.
Running benchmarks with COUNT = 500000 [tanh(x) for x in d] (Python implementation) took 0.758 seconds [fast_tanh(x) for x in d] (CPython C++ extension) took 0.076 seconds [fast_tanh2(x) for x in d] (PyBind11 C++ extension) took 0.204 seconds
시간 차이가 더 뚜렷해지도록 변수를 늘려
COUNT
보세요.또한 디버그 빌드는 최적화가 덜 하고 다양한 오류 검사를 포함하므로 C++ 모듈의 디버그 빌드는 릴리스 빌드보다 느리게 실행됩니다. 비교를 위해 빌드 구성 간에 전환해 보십시오. 하지만 릴리스 구성에 대해 이전에 설정한 속성을 업데이트해야 합니다.
주소 프로세스 속도 및 오버헤드
출력에서 PyBind11 확장은 순수 Python 구현보다 빠르지만 CPython 확장만큼 빠르지 않다는 것을 알 수 있습니다. 차이점의 주된 이유는 METH_O 플래그를 사용하기 때문입니다. 이 플래그는 여러 매개 변수, 매개 변수 이름 또는 키워드 인수를 지원하지 않습니다. PyBind11은 좀 더 복잡한 코드를 생성하여 호출자에게 Python과 유사한 인터페이스를 제공합니다. 테스트 코드는 함수를 500,000번 호출하므로 결과는 오버헤드를 크게 증폭시킬 수 있습니다.
루프를 네이티브 Python 코드로 이동하여 for
오버헤드를 더 줄일 수 있습니다. 이 방법은 반복기 프로토콜(또는 py::iterable
의 경우 PyBind11 형식)을 사용하여 각 요소를 처리하는 방법을 포함합니다. Python과 C++ 간의 반복적인 전환을 제거하는 것은 시퀀스를 처리하는 데 걸리는 시간을 줄이는 효과적인 방법입니다.
가져오기 오류 문제 해결
모듈을 ImportError
가져오려고 할 때 메시지가 표시되면 다음 방법 중 하나로 해결할 수 있습니다.
프로젝트 참조를 통해 빌드할 때 C++ 프로젝트 속성이 Python 프로젝트에 대해 활성화된 Python 환경과 일치하는지 확인합니다. Include(.h) 및 라이브러리(DLL) 파일에 동일한 폴더 위치가 사용되고 있는지 확인합니다.
출력 파일의 이름이 superfastcode.pyd와 같은 올바른지 확인합니다. 잘못된 이름 또는 확장명을 사용하면 필요한 파일을 가져올 수 없습니다.
setup.py 파일을 사용하여 모듈을 설치하는 경우, Python 프로젝트에 대해 활성화된 Python 환경에서
pip
명령을 실행해야 합니다. 솔루션 탐색기에서 프로젝트에 대한 활성 Python 환경을 확장하면 C++ 프로젝트에 대한 항목(예: superfastcode)이 표시됩니다.
C++ 코드 디버그
Visual Studio는 Python 및 C++ 코드를 함께 디버깅할 수 있습니다. 다음 단계에서는 superfastcode C++ 프로젝트에 대한 디버그 프로세스를 보여 주지만 이 프로세스는 superfastcode2 프로젝트에 대해 동일합니다.
솔루션 탐색기에서 Python 프로젝트를 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다.
속성 창에서 디버그 탭을 선택한 다음, 네이티브 코드 디버깅 사용> 옵션을 선택합니다.
팁 (조언)
네이티브 코드 디버깅을 사용하도록 설정하면 프로그램이 완료된 직후에 Python 출력 창이 닫히고 아무 키나 눌러 프롬프트 를 계속 표시하지 않고 종료될 수 있습니다. 네이티브 코드 디버깅을 사용하도록 설정한 후 일시 중지 및 프롬프트를 강제로 적용하려면
-i
탭의 인터프리터 인수> 필드에 인수를 추가 합니다. 이 인수는 코드가 실행된 후 Python 인터프리터를 대화형 모드로 전환합니다. 프로그램에서 Ctrl ++선택하여 창을 닫을 때까지 기다립니다. Python 프로그램의 끝에import os
및os.system("pause")
문을 추가하는 것이 다른 방법입니다. 이 코드는 원래 일시 중지 프롬프트를 복제합니다.파일>저장(또는 Ctrl+S)을 선택하여 속성 변경 내용을 저장합니다.
Visual Studio 도구 모음에서 빌드 구성을 디버그로 설정합니다.
코드는 일반적으로 디버거에서 실행하는 데 시간이 오래 걸리므로 Python 프로젝트
COUNT
파일의 변수를 기본값보다 약 5배 작은 값으로 변경할 수 있습니다. 예를 들어 500000 에서 1000000으로 변경합니다.C++ 코드에서 메서드의
tanh_impl
첫 번째 줄에 중단점을 설정합니다.디버그>디버깅 시작을 선택하여 디버거를 시작하거나 바로 가기 키 F5를 사용합니다.
중단점 코드가 호출되면 디버거가 중지됩니다. 중단점이 작동하지 않을 경우, 구성이 디버그로 설정되어 있는지 확인하고, 프로젝트를 저장하였는지 확인하십시오. 디버거를 시작할 때 프로젝트는 자동으로 저장되지 않습니다.
중단점에서 C++ 코드를 단계별로 실행하고 변수를 검사하는 등의 작업을 수행할 수 있습니다. 이러한 기능에 대한 자세한 내용은 Python 및 C++ 디버그를 함께 참조하세요.
대체 접근법
다음 표에 설명된 대로 다양한 방법으로 Python 확장을 만들 수 있습니다. 이 문서에서는 처음 두 행인 CPython
과 PyBind11
에 대해 설명합니다.
접근법 | 빈티지 | 대표 사용자 |
---|---|---|
에 대한 C/C++ 확장 모듈 CPython |
1,991 | 표준 라이브러리 |
PyBind11 (C++에 권장됨) | 2015 | |
Cython (C에 권장) | 2007 | gevent, kivy |
HPy | 2019 | |
mypyc | 2017 | |
ctypes | 2003 | oscrypto |
cffi | 2013 | 암호화, pypy |
SWIG | 1996 | crfsuite |
Boost.Python | 2002 | |
cppyy | 2017 |