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

PyConZA 2015: "How I learnt to stop worrying an...

Avatar for Pycon ZA Pycon ZA
October 02, 2015

PyConZA 2015: "How I learnt to stop worrying and love Boost.Python" by Bruce Merry

The Zen of Python dictates that there should be one - and preferably only one - obvious way to do something. However, when it comes to interoperation with C and C++, there is a multitude of options: the Python C API, Boost.Python, ctypes, cffi, Cython. I will describe my quest to find the right interface for a high-performance networking library.

The talk is largely a case study in applying Boost.Python, and will look at some issues such as the Global Interpreter Lock, handling KeyboardInterrupt cleanly, and managing object lifetime. I will briefly mention some of the alternative tools to explain why I settled on Boost.Python. It is not a complete Boost.Python tutorial, but rather aims to give a sense of the flavour and show how it's used in a real application.

For obvious reasons, this talk will have a lot of C++ code in it, and some familiarity with C++ will be useful.

Avatar for Pycon ZA

Pycon ZA

October 02, 2015
Tweet

More Decks by Pycon ZA

Other Decks in Programming

Transcript

  1. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary How I Learnt To Stop Worrying And Love Boost.Python An adventure in high-performance networking Bruce Merry SKA South Africa PyCon ZA 2015 1 / 50
  2. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Outline 1 Motivation MeerKAT SPEAD 2 Talking to C++ An Example C++ Library The Interface Zoo 3 Boost.Python That’s Easy! Object Lifetime Unicode Global Interpreter Lock 2 / 50
  3. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Outline 1 Motivation MeerKAT SPEAD 2 Talking to C++ An Example C++ Library The Interface Zoo 3 Boost.Python That’s Easy! Object Lifetime Unicode Global Interpreter Lock 3 / 50
  4. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary A MeerKAT Dish 4 / 50
  5. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Lots Of Dishes 5 / 50
  6. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Outline 1 Motivation MeerKAT SPEAD 2 Talking to C++ An Example C++ Library The Interface Zoo 3 Boost.Python That’s Easy! Object Lifetime Unicode Global Interpreter Lock 6 / 50
  7. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary High-performance Networking Streaming Protocol for Exchange of Astronomical Data Generic, not astronomy-specific at all Designed for moving numpy arrays around Used extensively in KAT-7 and MeerKAT Lossy one-way UDP transmission, multicast-friendly New library handles 20 Gbps in a single stream 7 / 50
  8. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Outline 1 Motivation MeerKAT SPEAD 2 Talking to C++ An Example C++ Library The Interface Zoo 3 Boost.Python That’s Easy! Object Lifetime Unicode Global Interpreter Lock 8 / 50
  9. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Code 1 namespace petshop { 2 3 class Parrot { 4 int volts; 5 public: 6 void voom(); 7 void set_volts(int volts); 8 int get_volts() const; 9 }; 10 11 } 9 / 50
  10. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Outline 1 Motivation MeerKAT SPEAD 2 Talking to C++ An Example C++ Library The Interface Zoo 3 Boost.Python That’s Easy! Object Lifetime Unicode Global Interpreter Lock 10 / 50
  11. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Python C API 1 #include "Python.h" 2 #include "petshop.h" 3 #include <memory> 4 5 typedef struct { 6 PyObject_HEAD 7 petshop::Parrot wrapped; 8 } Parrot; 9 10 static PyTypeObject ParrotType = { 11 PyVarObject_HEAD_INIT(NULL, 0) 12 "capi_petshop.Parrot" 13 }; 14 15 static PyObject * 16 Parrot_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { 17 Parrot *self = (Parrot *) type->tp_alloc(type, 0); 18 if (self != NULL) 19 { 20 new (&self->wrapped) petshop::Parrot(); 21 } 22 return (PyObject *) self; 23 } 24 25 static void Parrot_dealloc(Parrot *self) { 26 self->wrapped.~Parrot(); 27 Py_TYPE(self)->tp_free((PyObject *) self); 28 } 29 30 static PyObject *Parrot_voom(Parrot *self) { 31 self->wrapped.voom(); 32 Py_RETURN_NONE; 33 } 34 35 static PyObject *Parrot_get_volts(Parrot *self, void *closure) { 36 return PyLong_FromLong(self->wrapped.get_volts()); 37 } 38 39 static int 40 Parrot_set_volts(Parrot *self, PyObject *value, void *closure) { 41 long volts = PyLong_AsLong(value); 42 if (PyErr_Occurred()) 43 return -1; 44 if (volts < INT_MIN || volts > INT_MAX) { 45 PyErr_SetString(PyExc_OverflowError, 46 "Python int too large to convert to C int"); 47 return -1; 48 } 49 self->wrapped.set_volts(volts); 50 return 0; 51 } 52 53 static PyMethodDef Parrot_methods[] = { 54 {"voom", (PyCFunction) Parrot_voom, METH_NOARGS, "voom"}, 55 {NULL} 56 }; 57 58 static PyGetSetDef Parrot_getseters[] = { 59 {"volts", (getter) Parrot_get_volts, 60 (setter) Parrot_set_volts, "volts", NULL}, 61 {NULL} 62 }; 63 64 static struct PyModuleDef capi_petshop_module = { 65 PyModuleDef_HEAD_INIT, 66 "capi_petshop", 67 NULL, 68 -1, 69 NULL, 70 }; 71 72 extern "C" { 73 74 PyMODINIT_FUNC PyInit_capi_petshop(void) { 75 PyObject *m; 76 ParrotType.tp_new = Parrot_new; 77 ParrotType.tp_basicsize = sizeof(Parrot); 78 ParrotType.tp_flags = Py_TPFLAGS_DEFAULT; 79 ParrotType.tp_dealloc = (destructor) Parrot_dealloc; 80 ParrotType.tp_methods = Parrot_methods; 81 ParrotType.tp_getset = Parrot_getseters; 82 if (PyType_Ready(&ParrotType) < 0) 83 return NULL; 84 m = PyModule_Create(&capi_petshop_module); 85 if (m == NULL) 86 return NULL; 87 Py_INCREF(&ParrotType); 88 PyModule_AddObject(m, "Parrot", (PyObject *) &ParrotType); 89 return m; 90 } 91 } 11 / 50
  12. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Python C API 1 #include "Python.h" 2 #include "petshop.h" 3 #include <memory> 4 5 typedef struct { 6 PyObject_HEAD 7 petshop::Parrot wrapped; 8 } Parrot; 9 10 static PyTypeObject ParrotType = { 11 PyVarObject_HEAD_INIT(NULL, 0) 12 "capi_petshop.Parrot" 13 }; 14 15 static PyObject * 16 Parrot_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { 17 Parrot *self = (Parrot *) type->tp_alloc(type, 0); 18 if (self != NULL) 19 { 20 new (&self->wrapped) petshop::Parrot(); 21 } 22 return (PyObject *) self; 23 } 24 25 static void Parrot_dealloc(Parrot *self) { 26 self->wrapped.~Parrot(); 27 Py_TYPE(self)->tp_free((PyObject *) self); 28 } 29 30 static PyObject *Parrot_voom(Parrot *self) { 31 self->wrapped.voom(); 32 Py_RETURN_NONE; 33 } 34 35 static PyObject *Parrot_get_volts(Parrot *self, void *closure) { 36 return PyLong_FromLong(self->wrapped.get_volts()); 37 } 38 39 static int 40 Parrot_set_volts(Parrot *self, PyObject *value, void *closure) { 41 long volts = PyLong_AsLong(value); 42 if (PyErr_Occurred()) 43 return -1; 44 if (volts < INT_MIN || volts > INT_MAX) { 45 PyErr_SetString(PyExc_OverflowError, 46 "Python int too large to convert to C int"); 47 return -1; 48 } 49 self->wrapped.set_volts(volts); 50 return 0; 51 } 52 53 static PyMethodDef Parrot_methods[] = { 54 {"voom", (PyCFunction) Parrot_voom, METH_NOARGS, "voom"}, 55 {NULL} 56 }; 57 58 static PyGetSetDef Parrot_getseters[] = { 59 {"volts", (getter) Parrot_get_volts, 60 (setter) Parrot_set_volts, "volts", NULL}, 61 {NULL} 62 }; 63 64 static struct PyModuleDef capi_petshop_module = { 65 PyModuleDef_HEAD_INIT, 66 "capi_petshop", 67 NULL, 68 -1, 69 NULL, 70 }; 71 72 extern "C" { 73 74 PyMODINIT_FUNC PyInit_capi_petshop(void) { 75 PyObject *m; 76 ParrotType.tp_new = Parrot_new; 77 ParrotType.tp_basicsize = sizeof(Parrot); 78 ParrotType.tp_flags = Py_TPFLAGS_DEFAULT; 79 ParrotType.tp_dealloc = (destructor) Parrot_dealloc; 80 ParrotType.tp_methods = Parrot_methods; 81 ParrotType.tp_getset = Parrot_getseters; 82 if (PyType_Ready(&ParrotType) < 0) 83 return NULL; 84 m = PyModule_Create(&capi_petshop_module); 85 if (m == NULL) 86 return NULL; 87 Py_INCREF(&ParrotType); 88 PyModule_AddObject(m, "Parrot", (PyObject *) &ParrotType); 89 return m; 90 } 91 } Just Say No 11 / 50
  13. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Cython Overview Cython .pyx .pxd .c GCC .so 12 / 50
  14. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Cython Definition File c_petshop.pxd 1 cdef extern from "petshop.h" namespace "petshop": 2 cdef cppclass Parrot: 3 void voom() 4 void set_volts(int volts) 5 int get_volts() 13 / 50
  15. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Cython Wrapper cython_petshop.pyx 1 cimport c_petshop 2 3 cdef class Parrot: 4 cdef c_petshop.Parrot _this 5 6 def voom(self): 7 self._this.voom() 8 9 property volts: 10 def __get__(self): 11 return self._this.get_volts() 12 13 def __set__(self, volts): 14 self._this.set_volts(volts) 14 / 50
  16. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Cython Sometimes This Happens Error compiling Cython file: ------------------------------------------------------------ ... PyTypeObject *Py_TYPE(obj) bint PyMapping_Check(obj) object PyErr_Format(exc, const char *format, ...) @cname("__pyx_convert__from_py_spead::in::item") cdef item __pyx_convert__from_py_spead::in::item(obj) except *: ^ ------------------------------------------------------------ FromPyStructUtility:11:39: Expected an identifier or literal 15 / 50
  17. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Boost.Python 16 / 50
  18. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Boost.Python 1 #include <boost/python.hpp> 2 #include "petshop.h" 3 4 using namespace petshop; 5 using namespace boost::python; 6 7 BOOST_PYTHON_MODULE(bpy_petshop) 8 { 9 class_<Parrot>("Parrot") 10 .def("voom", &Parrot::voom) 11 .add_property("volts", 12 &Parrot::get_volts, &Parrot::set_volts); 13 } 16 / 50
  19. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Sir-Not-Appearing-In-These-Slides SWIG Understands C++ and templates Compiles to Python C API Quick glance at docs look promising! cffi, ctypes C only weave 17 / 50
  20. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Interface Summary Interface C++ PyPy No new lang Runtime C API % % " — Cython " % % — Boost.Python " % " Boost cffi % " " cffi ctypes % ( ") " — SWIG " % % ? 18 / 50
  21. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Outline 1 Motivation MeerKAT SPEAD 2 Talking to C++ An Example C++ Library The Interface Zoo 3 Boost.Python That’s Easy! Object Lifetime Unicode Global Interpreter Lock 19 / 50
  22. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Keyword And Default Arguments 1 .def("add_udp_reader", 2 &ring_stream_wrapper::add_udp_reader, 3 (arg("port"), 4 arg("max_size")=udp_reader::default_max_size, 5 arg("buffer_size")=udp_reader::default_buffer_size, 6 arg("bind_hostname")=std::string())) 20 / 50
  23. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Map C++ Exceptions 1 static void translate_exception_stop_iteration( 2 const stop_iteration &e) 3 { 4 PyErr_SetString(PyExc_StopIteration, e.what()); 5 } 6 ... 7 8 register_exception_translator<stop_iteration>( 9 &translate_exception_stop_iteration); 21 / 50
  24. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Operator Overloads 1 class_<flavour>("Flavour", ...) 2 .def(self == self) 3 .def(self != self); 22 / 50
  25. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Calling Python 1 namespace py = boost::python; 2 void heap_wrapper::add_item(py::object item) 3 { 4 std::int64_t id = p::extract<std::int64_t>( 5 item.attr("id")); 6 py::object buffer = item.attr("to_buffer")(); 7 ... 8 } 23 / 50
  26. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Wrappers For Python Builtins 1 class heap_wrapper : public heap 2 { 3 ... 4 py::list get_items() const 5 { 6 std::vector<item> base = heap::get_items(); 7 py::list out; 8 for (const item &it : base) 9 { 10 if (it.id != DESCRIPTOR_ID) 11 out.append(item_wrapper(it, self)); 12 } 13 return out; 14 } 15 ... 16 }; 24 / 50
  27. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Outline 1 Motivation MeerKAT SPEAD 2 Talking to C++ An Example C++ Library The Interface Zoo 3 Boost.Python That’s Easy! Object Lifetime Unicode Global Interpreter Lock 25 / 50
  28. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Refresher In CPython, objects have a reference count. Increment it to hold a reference. Decrement it to drop the reference. When it hits zero, object is deleted. Very easy to screw up with Python C API. 26 / 50
  29. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary C++ To The Rescue boost::python::handle is a smart wrapper Copy constructor increments the refcount Destructor decrements the refcount 27 / 50
  30. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary C++ To The Rescue boost::python::handle is a smart wrapper Copy constructor increments the refcount Destructor decrements the refcount Caution: not safe while release_gil active 27 / 50
  31. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Putting Things On Top Of Other Things What about C++ objects referencing other C++ objects? 1 class flowers { 2 public: 3 string name; 4 explicit flowers(const string &name) : name(name) {} 5 }; 6 7 class vase { 8 flowers *contents = nullptr; 9 public: 10 void set_contents(flowers &value) { 11 contents = &value; 12 } 13 14 string str() const { 15 return (contents ? contents->name : "empty"); 16 } 17 }; 28 / 50
  32. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Naïve Wrapping 1 BOOST_PYTHON_MODULE(custodian1) { 2 using namespace boost::python; 3 class_<flowers>("Flowers", init<string>()); 4 class_<vase>("Vase") 5 .def("set_contents", &vase::set_contents) 6 .def("__str__", &vase::str); 7 } 29 / 50
  33. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Naïve Wrapping 1 BOOST_PYTHON_MODULE(custodian1) { 2 using namespace boost::python; 3 class_<flowers>("Flowers", init<string>()); 4 class_<vase>("Vase") 5 .def("set_contents", &vase::set_contents) 6 .def("__str__", &vase::str); 7 } >>> from custodian import * >>> v = Vase() >>> str(v) ’empty’ >>> v.set_contents(Flowers(’tulips’)) >>> str(v) Segmentation fault 29 / 50
  34. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Custodians And Wards Let’s tell Boost.Python about the relationship: 1 BOOST_PYTHON_MODULE(custodian) { 2 using namespace boost::python; 3 class_<flowers>("Flowers", init<string>()); 4 class_<vase>("Vase") 5 .def("set_contents", &vase::set_contents, 6 with_custodian_and_ward_postcall<1, 2>()) 7 .def("__str__", &vase::str); 8 } 30 / 50
  35. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Custodians And Wards What Happened? weakref Vase life support Flowers weak callback 31 / 50
  36. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Help, My Python Is Leaking! What Happens Here? 1 v = Vase() 2 for line in f: 3 v.set_contents(Flowers(line)) 32 / 50
  37. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary A More Direct Approach Let’s make vase explicitly hold a reference to flowers. 1 class vase { 2 flowers *contents = nullptr; 3 public: 4 handle<> flowers_handle; 5 6 void set_contents(flowers &value) { 7 contents = &value; 8 } 9 10 string str() const { 11 return (contents ? contents->name : "empty"); 12 } 13 }; 33 / 50
  38. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Storing A Handle spead2 implements a call policy for this: 1 class_<vase>("Vase") 2 .def("set_contents", &vase::set_contents, 3 store_handle_postcall< 4 vase, &vase::flowers_handle, 1, 2>()) 5 .def("__str__", &vase::str); See spead2 source for store_handle_postcall implementation. 34 / 50
  39. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Caution Caution: don’t create cycles involving C++ objects Python can’t garbage collect such cycles C API has a solution to this, but Boost.Python doesn’t expose it 35 / 50
  40. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Outline 1 Motivation MeerKAT SPEAD 2 Talking to C++ An Example C++ Library The Interface Zoo 3 Boost.Python That’s Easy! Object Lifetime Unicode Global Interpreter Lock 36 / 50
  41. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Quick Reminder Python 2 Python 3 Purpose str / bytes bytes Encoded byte sequence unicode str Unicode code points 37 / 50
  42. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary What Would Boost.Python Do? Python 2 str ↔ std::string Python 3 str ↔ std::string, UTF-8 bytes → std::string 38 / 50
  43. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary What Would Boost.Python Do? Python 2 str ↔ std::string Python 3 str ↔ std::string, UTF-8 bytes → std::string What if I want std::string → bytes? 38 / 50
  44. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Custom Converters We’ll define a new C++ class for this. 1 class bytestring : public std::string { 2 { 3 public: 4 using std::string::string; 5 6 bytestring(const std::string &s) 7 : std::string(s) {} 8 bytestring(std::string &&s) 9 : std::string(std::move(s)) {} 10 }; This is just a class interchangeable with std::string. 39 / 50
  45. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Custom Converters Define how to convert it to Python1: 1 class bytestring_to_python 2 { 3 public: 4 static PyObject *convert(const bytestring &s) 5 { 6 return PyBytes_FromStringAndSize( 7 s.data(), s.size()); 8 } 9 }; Register the converter 1 to_python_converter<bytestring, bytestring_to_python>(); 1only Python 3 version shown 40 / 50
  46. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Outline 1 Motivation MeerKAT SPEAD 2 Talking to C++ An Example C++ Library The Interface Zoo 3 Boost.Python That’s Easy! Object Lifetime Unicode Global Interpreter Lock 41 / 50
  47. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Why do we care? Python threads hold the GIL while executing. Waiting for a heap should not block other threads 42 / 50
  48. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Why do we care? Python threads hold the GIL while executing. Waiting for a heap should not block other threads Non-Python threads calling Python code 42 / 50
  49. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Releasing the GIL, C++-style 1 class release_gil { 2 PyThreadState *save; 3 public: 4 release_gil() { 5 save = PyEval_SaveThread(); 6 } 7 8 ~release_gil() { 9 PyEval_RestoreThread(save); 10 } 11 }; 43 / 50
  50. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Acquiring the GIL, C++ style 1 class acquire_gil { 2 PyGILState_STATE gstate; 3 public: 4 acquire_gil() { 5 gstate = PyGILState_Ensure(); 6 } 7 8 ~acquire_gil() { 9 PyGILState_Release(gstate); 10 } 11 }; 44 / 50
  51. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary KeyboardInterrupt Consider a simple synchronous receiver loop: 1 for heap in stream: 2 do_stuff_with(heap) What happens if I hit Ctrl-C? Ideally, KeyboardInterrupt exception. 45 / 50
  52. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary KeyboardInterrupt Consider a simple synchronous receiver loop: 1 for heap in stream: 2 do_stuff_with(heap) What happens if I hit Ctrl-C? Ideally, KeyboardInterrupt exception. Early in spead2 development, nothing until next heap. 45 / 50
  53. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary If I Can Just Interrupt You There... A POSIX solution: Signal handlers interrupt system calls (EINTR) PyErr_CheckInterrupts gives interrupt handles a chance to run. Return -1 if handler threw an exception 46 / 50
  54. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary If I Can Just Interrupt You There... General pattern: 1 while (true) { 2 release_gil gil; 3 int result = blocking_syscall(); 4 if (result == -1) { 5 if (errno == EINTR) { 6 gil.acquire(); 7 if (PyErr_CheckSignals() == -1) 8 throw boost::python::error_already_set(); 9 } 10 else { 11 gil.acquire(); 12 PyErr_SetFromErrno(PyExc_OSError); 13 throw boost::python::error_already_set(); 14 } 15 } 16 else 17 break; 18 } 47 / 50
  55. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Summary The Good Fantastic for integrating C++ classes 48 / 50
  56. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Summary The Good Fantastic for integrating C++ classes Can drop down to Python C API when needed 48 / 50
  57. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Summary The Good Fantastic for integrating C++ classes Can drop down to Python C API when needed No new language to learn 48 / 50
  58. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Summary The Not So Good Introduces a system library dependency 2as far as I know 49 / 50
  59. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Summary The Not So Good Introduces a system library dependency Lots of deep metaprogramming magic 2as far as I know 49 / 50
  60. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Summary The Not So Good Introduces a system library dependency Lots of deep metaprogramming magic Doesn’t support all C API functionality 2as far as I know 49 / 50
  61. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Summary The Not So Good Introduces a system library dependency Lots of deep metaprogramming magic Doesn’t support all C API functionality Doesn’t support PyPy2 2as far as I know 49 / 50
  62. Boost.Python Bruce Merry Motivation MeerKAT SPEAD Talking to C++ An

    Example C++ Library The Interface Zoo Boost.Python That’s Easy! Object Lifetime Unicode GIL Summary Questions Slides and code samples: https: //github.com/bmerry/pyconza2015-bpy spead2: https://github.com/ska-sa/spead2 50 / 50