queues python performance data-structures benchmarking deque

queues - python: comparación de rendimiento de deque frente a lista



queue class python (2)

En python docs puedo ver que deque es una colección especial altamente optimizada para mostrar / agregar elementos desde el lado izquierdo o derecho. Por ejemplo, la documentación dice:

Deques son una generalización de stacks y colas (el nombre se pronuncia "deck" y es la abreviatura de "double-ended queue"). Deques es compatible con la seguridad de subprocesos, la memoria eficiente se agrega y emerge de cualquier lado del deque con aproximadamente el mismo rendimiento de O (1) en cualquier dirección.

Aunque los objetos de lista admiten operaciones similares, están optimizados para operaciones rápidas de longitud fija e incurren en costos de movimiento de memoria O (n) para operaciones pop (0) e inserción (0, v) que cambian tanto el tamaño como la posición de la representación de datos subyacente .

Decidí hacer algunas comparaciones usando ipython . ¿Alguien podría explicarme qué hice mal aquí?

In [31]: %timeit range(1, 10000).pop(0) 10000 loops, best of 3: 114 us per loop In [32]: %timeit deque(xrange(1, 10000)).pop() 10000 loops, best of 3: 181 us per loop In [33]: %timeit deque(range(1, 10000)).pop() 1000 loops, best of 3: 243 us per loop


Por lo que vale la pena:

> python -mtimeit -s ''import collections'' -s ''c = collections.deque(xrange(1, 100000000))'' ''c.pop()'' 10000000 loops, best of 3: 0.11 usec per loop > python -mtimeit -s ''c = range(1, 100000000)'' ''c.pop()'' 10000000 loops, best of 3: 0.174 usec per loop > python -mtimeit -s ''import collections'' -s ''c = collections.deque()'' ''c.appendleft(1)'' 10000000 loops, best of 3: 0.116 usec per loop > python -mtimeit -s ''c = []'' ''c.insert(0, 1)'' 100000 loops, best of 3: 36.4 usec per loop

Como puede ver, donde realmente brilla está en appendleft vs insert .


Could anyone explain me what I did wrong here

Sí, su tiempo está dominado por el tiempo para crear la lista o deque. El tiempo para hacer pop es insignificante en comparación.

En su lugar, debe aislar la cosa que está intentando probar (la velocidad del pop) desde el tiempo de configuración:

In [1]: from collections import deque In [2]: s = range(1000) In [3]: d = deque(s) In [4]: s_append, s_pop = s.append, s.pop In [5]: d_append, d_pop = d.append, d.pop In [6]: %timeit s_pop(); s_append(None) 10000000 loops, best of 3: 115 ns per loop In [7]: %timeit d_pop(); d_append(None) 10000000 loops, best of 3: 70.5 ns per loop

Dicho esto, las diferencias reales entre los deques y la lista en términos de rendimiento son:

  • Deques tienen O (1) velocidad para appendleft () y popleft () mientras que las listas tienen O (n) rendimiento para insert (0, value) y pop (0) .

  • El rendimiento de la lista de anexos es inconsistente porque usa realloc () debajo del capó. Como resultado, tiende a tener tiempos excesivamente optimistas en código simple (porque el realloc no tiene que mover datos) y tiempos realmente lentos en el código real (porque la fragmentación obliga a realloc a mover todos los datos). Por el contrario, el rendimiento de deque de anexar es consistente porque nunca reasigna y nunca mueve datos.