Serpy : sérialisation d’objets Python ridiculement rapide

Francois Schneider
Feb 22 · 4 min read

serpy: ridiculously fast object serialization

Ok, ma traduction est hasardeuse mais cela annonce la couleur. D’ailleurs, l’auteur annonce des performances assez significatives en comparaison à d’autres solutions (voir le benchmark) qui semblent justifier cette description quelque peu provocante.

Je suis tombé sur cette librairie Serpy (ridiculously fast object serialization) un jour où je faisais face à de gros problèmes de performances sur la sérialisation d’une réponse API REST.

Alors Serpy c’est quoi ?

Serpy, késako ?

Dans cet objectif, Serpy a été conçu pour sérialiser simplement et surtout très rapidement des données complexes vers des types natifs (dicts, lists, string…). Ainsi, les types natifs peuvent être convertis aisément en JSON, par exemple.

Génial non ? Oui, mais attention, il ne sait faire que ça. Je m’explique.

Le système de sérialisation fourni par Django Rest Framework permet de traiter à la fois les étapes de sérialisation et de désérialisation. Ce système est utilisé de manière analogue à un formulaire Django. Il inclue donc l’étape de validation des données entrantes, indispensable pour que la déserialisation fonctionne correctement. A ça vous ajoutez une once de magie Django et vous pouvez, à partir du modèle Django, écrire en très peu de lignes votre sérialiseur. Mais cette polyvalence et cette magie ont un prix : LES PERFORMANCES.

Tant qu’on a très peu de données à sérialiser, l’impact est très faible. Par contre, si on a une API qui doit retourner une liste de resources complexes, la magie et la polyvalence se “payent cash” par une chute vertigineuse des performances.

Mais je pose la question : que gagne-t-on à faire appel à une couche permettant de valider des données et désérialiser des données entrantes, quand on a juste besoin de les sérialiser ?

La réponse est simple : RIEN !

Serpy entre donc en jeu en se concentrant sur la sérialisation uniquement. En s’affranchissant des étapes de validation nécessaires à la désérialisation, on recupère beaucoup de perfs. La doc annonce un ordre de grandeur (x10). C’est au minimum le gain qui sera constaté. Cela conduit en revanche à avoir des couches de sérialisation et de désérialisation hétérogènes, mais quand tout cela est testé automatiquement, ce n’est pas très impactant au niveau maintenance.

Serpy, à quoi ça ressemble ?

Prenons, par exemple, ces modèles Django :

from django.db import modelsclass ProductionCompany(models.Model):
name = models.CharField()
class Singer(models.Model):
name = models.CharField()
production_company = ProductionCompany()
class Album(models.Model):
name = models.CharField()
singer = models.ForeignKey(Singer)
class Track(models.Model):
rank = models.IntegerField()
name = models.CharField()
album = models.ForeignKey(Album, related_name="tracks")

A présent, écrivons les sérialiseurs correspondants :

NB : cet article n’a pas pour vocation d’expliquer la syntaxe Serpy, je vous invite à consulter la documentation officielle pour plus de détails.

import serpy
class ProductionCompanySerializer(serpy.SerpySerializer):
name = serializer.Field()
class SingerSerializer(serpy.SerpySerializer):
name = serializer.Field()
production_company = ProductionCompanySerializer()
class TrackSerializer(serpy.SerpySerializer):
rank = serializer.IntField()
name = serializer.Field()
class AlbumSerializer(serpy.SerpySerializer):
name = serializer.Field()
singer = SingerSerializer()
tracks = serializer.MethodField()
def get_tracks(cls, o):
result = []
for track in o.tracks.all():
result.append(TrackSerializer(track).data)
return result

Comme on peut le voir, il n’y pas de magie mais Serpy nous permet quand même d’écrire assez rapidement et facilement nos sérialiseurs.

Et maintenant, voyons comment utiliser un serialiseur Serpy :

from serializer import AlbumSerializeralbums = Album.objects.all()
serialized_albums = AlbumSerializer(albums, many=True)
dict_albums = serialized_albums.data

La syntaxe est identique à celle de Django Rest Framework ce qui facilite grandement son utilisation.

Serpy, la solution miracle ?

C’est beaucoup plus rapide (entre 18 et 20 fois) qu’un sérialiseur de Django Rest Framework. Et une fois l’écriture des sérialiseurs effectués, son utilisation est identique à ceux de Django Rest Framework.

Chez Wedge, nous nous appuyons par défaut sur Serpy pour sérialiser nos données, afin d’anticiper les futurs enjeu de performance. Nous nous servons uniquement des sérialiseurs Django Rest Framework pour valider les données en entrée.

Non

Cela demande de bien optimiser le QuerySet que l’on fournit en entrée pour en tirer toute sa puissance. Or, c’est vite fastidieux d’identifier comment le faire quand vous avez un serialiseur qui utilise des serialiseurs qui eux-mêmes utilisent des sérialiseurs et ainsi de suite.

Et là vous me direz :

“- Bah, les sérialiseurs DRF ne permettent pas de faire mieux ? “

“- C’est pas faux !”

“- Alors, pourquoi non ? “

“- Et bien simplement pour pouvoir teaser mon prochain article… 😉”

Django Rest Framework : Serpy serialiseur et optimisation Django ORM

Wedge Digital

Créer vos produits digitaux sans risque ✌️

Wedge Digital

Le quotidien, les retours, impressions et tips d’une équipe de devs passionnée de tech

Francois Schneider

Written by

Entrepreneur, fan de Pyhon / VueJs et gamer quand il reste du temps

Wedge Digital

Le quotidien, les retours, impressions et tips d’une équipe de devs passionnée de tech