Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Extending Python with Compiled Languages

Extending Python with Compiled Languages

Avatar for Iskander (Alex) Sharipov

Iskander (Alex) Sharipov

November 30, 2019
Tweet

More Decks by Iskander (Alex) Sharipov

Other Decks in Programming

Transcript

  1. C/C++ • Python native libraries • Basically a C shared

    libraries • Python working perfectly with C/C!++ shared libraries • C functions are needed to be wrapped with python-compatible functions using python C API 5
  2. Code typedef struct { int length; int *values; } Array;

    Array *SieveOfEratosthenes(int n) 6 C/CExtExample.c
  3. Add Python Support • Include Python.h • Wrap functions with

    python-compatible wrappers • Define array of methods • Define PyModuleDef • Create function PyInit_<name> that returns PyModuleDef 7
  4. Add Python Support PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, …);

    PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords( PyObject *, PyObject *, const char *, char **, ...); https://docs.python.org/3/c-api/arg.html 11
  5. Add Python Support C/CExtExample.c static PyMethodDef Methods[] = { {“sieve_of_eratosphenes",

    CExtExample_SieveOfEratosphenes, METH_VARARGS, "Return list of prime numbers until given number."}, {NULL, NULL, 0, NULL} "/* Sentinel "*/ }; 13
  6. Add Python Support C/CExtExample.c static PyModuleDef CExtExample = { PyModuleDef_HEAD_INIT,

    "CExtExample", "Example module written in C", -1, Methods}; 14
  7. Setup   esharifu  $ ~/projects  python3 %--version

    Python 3.7.5   esharifu  $ ~/projects  clang -v Apple clang version 11.0.0 (clang-1100.0.20.17) Target: x86_64-apple-darwin18.6.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/ usr/bin 16
  8. Building from setuptools import setup, Extension extension = Extension('CExtExample', sources=['CExtExample.c'])

    setup(name='CExtExample', version='1.0', description='This is Example module written in C', ext_modules=[extension]) C/setup.py 17
  9. Building $ ~/p/E/C  nm CExtExample.cpython-37m-darwin.so 0000000000001050 d _CExtExample 0000000000000dd0

    t _CExtExample_SieveOfEratosphenes 00000000000010c0 d _Methods 0000000000000db0 T _PyInit_CExtExample U _PyList_Append U _PyList_New U _PyLong_FromLong U _PyModule_Create2 U %__PyArg_ParseTuple_SizeT U _free U _malloc U dyld_stub_binder 18
  10. Memory Management • Do not use malloc/free on python objects

    • Use Py<StructName>_New instead • Python have it’s own allocator and own private heap • You can use malloc/free on c structures 19
  11. Go • Compiling Go code to shared libraries • Using

    CGo • CGo !!= Go • Use Go shared library in C extension 23
  12. Add Python Support • Import C • Include Python.h •

    Wrap go functions to CGo-compatible wrappers • Include Python.h • Wrap functions with python-compatible wrappers • Define array of methods • Define PyModuleDef • Create function PyInit_<name> that returns PyModuleDef 25
  13. Add Python Support pt. 1 // #cgo pkg-config: python3 //

    #include <Python.h> import "C" Go/GoExtExample.go 26
  14. Add Python Support pt. 1 // SieveOfEratosphenes calculates prime numbers

    //export SieveOfEratosphenes func func SieveOfEratosphenes(n int, result *[]int) { … } Go/GoExtExample.go 27
  15. Setup   esharifu  $ ~/projects  python3 %--version

    Python 3.7.5   esharifu  $ ~/projects  go version go version go1.13.1 darwin/amd64 28
  16. Add Python Support pt. 2 #define PY_SSIZE_T_CLEAN #include <Python.h> #include

    "GoExtExampleGo.h" #if PY_MAJOR_VERSION >= 3 Go/GoExtExample.c 30
  17. Add Python Support pt. 2 Go/GoExtExample.c static PyObject *GoExtExample_SieveOfEratosphenes(PyObject *self,

    PyObject *args) { int n; if (!PyArg_ParseTuple(args, "I", &n)) { return NULL; } GoSlice primes = {}; SieveOfEratosphenes((GoInt)n, &primes); PyObject *result = PyList_New(0); for (int i = 0; i < primes.len; i"++) { GoInt current = ((GoInt *)(primes.data))[i]; PyList_Append(result, PyLong_FromLong(current)); } return result; } 31
  18. Building pt. 2 gcc GoExtExample.c -dynamiclib GoExtExampleGo.so -o \ GoExtExample.so

    \ $(python3-config —cflags) \ $(python3-config --ldflags) 32
  19. Pros & Cons • Unable to use Go tooling •

    Unable return go structs from go funcs and multiple values • Possible memory leaks • Blocking goroutines during CGo calls • Unable to cross-compile • A bunch of side effects from CGo 33
  20. Memory Management • https:!//karthikkaranth.me/blog/calling-c- code-from-go/ • Python and Go both

    have private heaps • GC of both languages operates only inside it’s private heap and knows only about objects it allocated 34
  21. Benchmarks import pytest import GoExtExample @pytest.mark.parametrize("input", [1000, 100000, 1000000]) def

    test_go(benchmark, input): benchmark(GoExtExample.sieve_of_eratosphenes, input) Go/test_benchmark.py 36
  22. Why? • Speed(Not Guaranteed) • Avoiding GIL • Step-by-step migration

    from Python • Using language-specific libraries 39
  23. Why Not? • Easy way to shot to your leg

    • Harder Memory Management 40