29
Un serveur métier en Python / C++ Meet-up C++ 02/10/2014 Pierre Marquis & Alexandre Bonnasseau

Comment développer un serveur métier en python/C++

  • Upload
    cppfrug

  • View
    180

  • Download
    2

Embed Size (px)

Citation preview

Page 1: Comment développer un serveur métier en python/C++

Un serveur métier en Python / C++Meet-up C++ 02/10/2014Pierre Marquis & Alexandre Bonnasseau

Page 2: Comment développer un serveur métier en python/C++

Plan

• Retour d’expérience

• En pratique, quelques lignes de code

Page 3: Comment développer un serveur métier en python/C++

L'équipe dev carto

Info trafic

Itinéraire

Plan

Géolocalisation

Moteur de suggestion

Moteur de recherche géolocalisée

Itinéraire transports en commun

Page 4: Comment développer un serveur métier en python/C++

Python WTF ??!

Page 5: Comment développer un serveur métier en python/C++

Python WTF ??!

- Simplicité de code

- Framework web léger

- Richesse des modules

- Facilité d'industrialisation

Page 6: Comment développer un serveur métier en python/C++

Notre philosophie

- Python quand on peut

- C++ quand c’est nécessaire

Page 7: Comment développer un serveur métier en python/C++

Chemin de l’équipe

● Fonctions plus atomiques● Test U● Lint● Dojo● Pair programming● Code review

Page 8: Comment développer un serveur métier en python/C++

Schéma d’archi du plan

Page 9: Comment développer un serveur métier en python/C++

Chaîne d’industrialisation

Page 10: Comment développer un serveur métier en python/C++

Aujourd’hui

+ 80% des serveurs migrés

+ Langage très intéressant

+ Framework mieux maîtrisé

+ Dev plus rapide

+ Plus d’agilité

- Moins de maîtrise C++

- Multithread

- Débogage binding

Page 11: Comment développer un serveur métier en python/C++

En pratique :appeler du C++ depuis Python

Page 12: Comment développer un serveur métier en python/C++

Cadre

– Existence d’une base de code C++ fiable et testée

– On souhaite prototyper rapidement (besoin mouvant)

– Besoin d’exécution rapide pour des fonctions critiques

Page 13: Comment développer un serveur métier en python/C++

L'existant#define _USE_MATH_DEFINES

#include <cmath>

#include "geo.hpp"

#include <sstream>

#include <stdexcept>

string geocoord2string(double angle) {

if ( (angle > 180) || (angle < -180) )

throw invalid_argument("Invalid argument : angle must be beetween -180° and

180°");

int deg = int(floor(angle));

double rest = angle - deg;

int minute = int(floor( rest * 60));

rest = rest * 60 - minute;

int second = int(floor( rest * 60));

ostringstream result;

result << deg << "° " << minute << "' " << second <<"''";

return result.str();

}

double deg2rad(double deg) {

return (deg * M_PI / 180);

}

GeoPoint::GeoPoint(double lat, double lng) : lat(lat), lng(lng) {}

double GeoPoint::distance(const GeoPoint &other) {

double nDLat = deg2rad(other.lat - this->lat);

double nDLon = deg2rad(other.lng - this->lng);

double thisLatRad = deg2rad(this->lat);

double otherLatRad = deg2rad(other.lat);

double nA = pow ( sin(nDLat/2), 2 ) + cos(thisLatRad) * cos(otherLatRad) * pow ( sin(nDLon/2), 2 );

double nC = 2 * atan2( sqrt(nA), sqrt( 1 - nA ));

double nD = EARTH_RADIUS * nC;

return nD; // Return our calculated distance}

Page 14: Comment développer un serveur métier en python/C++

Objectif

Utiliser les fonctions C++ en python :

Projet complet disponible sur github :

https://github.com/Mappy/un-serveur-metier-en-python-cpp

$ pythonPython 2.7.3>>> import geo>>> print geo.geocoord2string(5.36)5° 21’ 36‘’

Page 15: Comment développer un serveur métier en python/C++

Un module python écrit en C++

D'après : https://docs.python.org/2/extending/extending.html

geomodule.cpp#include "Python.h"#include "geo.hpp"

static PyObject * geocoord2string_py(PyObject *self, PyObject *args){ double angle = 0; if (!PyArg_ParseTuple(args, "d", &angle)) return NULL; string res = geocoord2string(angle); return Py_BuildValue("s", res.c_str());}

// La liste des fonctions qu'on expose en Pythonstatic PyMethodDef geoMethods[] = { { "geocoord2string", geocoord2string_py, METH_VARARGS, "Convert a latitude or a longitude as an angle in a string in the form : d° m' s''." }, { NULL, NULL, 0, NULL } /* Sentinel */};

// La fonction initnomdumodule est appelée par l'interpréteur Python // à l'import du modulePyMODINIT_FUNC initgeo(void){ (void) Py_InitModule("geo", geoMethods);}

Page 16: Comment développer un serveur métier en python/C++

Avec Boost.Python ?

geomudule.cpp

… C’est tout !

#include <boost/python.hpp>#include <boost/python/module.hpp>#include "geo.hpp"

using namespace boost::python;BOOST_PYTHON_MODULE(geo){ def("geocoord2string", geocoord2string); class_<GeoPoint>("GeoPoint", init<double, double>()) .def("distance", &GeoPoint::distance) ;}

Page 17: Comment développer un serveur métier en python/C++

Avec Boost.Python, on peut

– Exposer des fonctions C++ en Python

– Exposer des classes C++ en Python

– Choisir quelles méthodes exposer pour une classe

– Utiliser Boost::optional pour gérer les paramètres optionnels

Page 18: Comment développer un serveur métier en python/C++

Packager une extension Python

Le fichier setup.py s’occupe de la compilation :

Installer avec :

python setup.py install

Ou packager :

python setup.py bdist

from distutils.core import setup, Extension

geo_module = Extension('geo', include_dirs = ['/usr/local/include',], library_dirs = ['/usr/local/lib',], extra_compile_args=['-std=c++11'], sources = ['geomodule.cpp', 'geo.cpp'])

setup (name = 'Geo', version = '1.0', description = 'A geo package from Mappy', author = 'LBS team', author_email = '[email protected]', url = 'http://github.com/mappy', long_description = ‘A demo package with geo functions', ext_modules = [geo_module])

Page 19: Comment développer un serveur métier en python/C++

Focus : Gestion de la mémoire

– Un code C++ qui conserve une référence sur un objet Python doit appeler la macro Py_INCREF() pour s'assurer que l'objet ne sera pas détruit

– Il faut appeler Py_DECREF() pour libérer l'objet

Page 20: Comment développer un serveur métier en python/C++

Focus : Gestion des erreurs

Le code suivant lève une exception C++ :

import geo

print geo.geocoord2string(181)

Sans Boost.Python :

terminate called after throwing an instance of 'std::invalid_argument'

what(): Invalid argument : angle must be beetween -180° and 180°

Avec Boost.Python :

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

ValueError: Invalid argument : angle must be beetween -180° and 180°

Boost.Python permet également d'affiner la gestion des erreurs en associant des erreurs spécifiques Python aux exceptions C++

Page 21: Comment développer un serveur métier en python/C++

Un serveur de distance géographiquesgeoserveur.py

A lancer par : python geoserver.py

Tester l’url : http://localhost:8888/distance/48.85,2.35/43.30,5.38

from bottle import route, run, templatefrom geo import GeoPoint

@route('/distance/<lat1:float>,<lng1:float>/<lat2:float>,<lng2:float>')def index(lat1, lng1, lat2, lng2): dep = GeoPoint(lat1, lng1) arr = GeoPoint(lat2, lng2) return template("Distance = {{distance}}", distance=dep.distance(arr))

run(host='localhost', port=8888)

Page 22: Comment développer un serveur métier en python/C++

Une autre approche : Producteur / Consommateur

– Le code python peut appeler des méthodes C++ à distance

– Par exemple via un bus RabbitMQ ou bien des appels distants ZMQ

–  Au final, le code Python délègue l‘exécution des sections critiques à des workers C++

Page 23: Comment développer un serveur métier en python/C++

Les difficultés en Python quand on vient du C++

Page 24: Comment développer un serveur métier en python/C++

Typage dynamique

– En C++ le typage statique offre une première validation du code

– En Python, on ne détecte les erreurs de type qu'à l'exécution !

Þ il faut exécuter le code pour le tester

Þ les tests unitaires sont indispensables !

Page 25: Comment développer un serveur métier en python/C++

Threads

– Le Global Interpreter Lock (GIL) assure que les traitements concurrents ne se marchent pas dessus :

https://docs.python.org/2/glossary.html#term-global-interpreter-lock

http://dabeaz.blogspot.fr/2010/01/python-gil-visualized.html

– Les modules thread / threading

– encapsulent les primitives système de thread

– fournissent des primitives de synchronisation : verrous, sémaphores, etc.

– ... Mais à aucun moment deux instructions peuvent être exécutées en même temps à cause du GIL !

Þ Mieux vaut utiliser multiprocessing

Page 26: Comment développer un serveur métier en python/C++

 Mémoire partagée

– Le module mmap (Memory-mapped file) permet de partager de la mémoire entre plusieurs process

– On peut accéder à cette mémoire comme un fichier en lecture / écriture

 

– On accède à cette mémoire comme un tableau de char

 

– Mais on ne peut pas utiliser de types complexes (listes, dictionnaires, objets définis sur mesures)

Þ Pas aussi souple qu’en C++

Page 27: Comment développer un serveur métier en python/C++

Conclusion

Page 28: Comment développer un serveur métier en python/C++

Où va Mappy ?

– Amélioration continue de l’outillage

– Nouveaux services asynchrones en Python

– … Et bientôt un nouveau serveur d'itinéraire en Python / C++ ?

Page 29: Comment développer un serveur métier en python/C++

Merci

Enjoy : http://fr.mappy.com/

Pierre Marquis : [email protected]

Alexandre Bonnasseau : https://github.com/abonnasseau