4 votes

Performance de bytearray et alternatives

Je suis en train d'écrire un analyseur pour un protocole fonctionnant sur TCP.

Certains messages sont divisés entre plusieurs paquets, donc je dois être capable de "jeter un œil" dans mon flux avec la possibilité de revenir en arrière et aussi d'ajouter les données entrantes à la fin. D'un autre côté, j'aimerais pouvoir supprimer le contenu des paquets que j'ai analysés avec succès.

  • Le problème avec bytes est que l'ajout nécessite une copie (pas dans CPython, mais alors il est aussi impossible de supprimer les premiers octets dans un objet immuable).
  • Le problème avec bytearray est que vider les octets déjà vus nécessite également une copie (ou du moins c'est ce que je pensais, voir ci-dessous)
  • Le problème avec collections.deque est l'énorme besoin en mémoire. Même chose avec list.

Cependant, j'ai fait des tests avec bytearray et il semble que l'opération pop(0) soit bien plus efficace qu'avec les listes:

from time import time

n = 100000

for container in [bytearray, list]:
    print(container)

    a = container(b'a'*n)
    t = time()
    for i in range(n):
        del a[0]
    print('del a[0]', time() - t)

    a = container(b'a'*n)
    t = time()
    for i in range(n):
        del a[-1]
    print('del a[-1]', time() - t)

    a = container(b'a'*n)
    t = time()
    for i in range(n-1):
        del a[1]
    print('del a[1]', time() - t)

    a = container(b'a'*n)
    t = time()
    for i in range(n-1):
        del a[-2]
    print('del a[-2]', time() - t)

    print()

Il semble que del a[0] et del a[-1] ont à peu près la même complexité pour bytearray, en cpython2, cpython3 et pypy3.

J'aimerais savoir:

  1. Comment est-ce possible ? Y a-t-il un moyen plus efficace que del a[:k] pour supprimer les premiers k octets ?

  2. Existe-t-il une structure de données plus efficace que le bytearray ? (peut-être en utilisant array, memoryview ou ctypes)

0voto

ivan_pozdeev Points 2233

Python sacrifie délibérément les performances du code pour les performances du programmeur.

Utilisez ce qui est le plus pratique à utiliser.

Quand vous avez une implémentation fonctionnant correctement et que les performances s'avèrent insuffisantes, remplacez seulement les parties critiques (comme indiqué par le profilage) par des équivalents plus rapides. Consultez https://wiki.python.org/moin/PythonSpeed/PerformanceTips#Overview:_Optimize_what_needs_optimizing pour plus d'informations.


Cela dit, un candidat idéal pour le cas d'utilisation que vous avez décrit serait un "tampon segmenté" qui renverrait des tranches de manière transparente à partir d'une série de tampons.

Extraire des données nécessitera toujours une copie (car tous les types Python standard possèdent leur mémoire), et vous aurez des frais généraux d'interprétation si vous implémentez le type en pur Python. Ainsi, pour obtenir une amélioration significative, vous devrez probablement passer à Cython/C ou quelque chose du genre. C'est pourquoi il est si important de bien concevoir d'abord l'ensemble -- en pur Python, il est beaucoup plus facile de modifier les choses.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X