Forma idiomática de hacer lista / dict en Cython?


Mi problema: He encontrado que procesar grandes conjuntos de datos con C++ raw usando el mapa y vector STL a menudo puede ser considerablemente más rápido (y con menor huella de memoria) que usar Cython.

Me imagino que parte de esta penalización de velocidad se debe al uso de listas y dictados de Python, y que podría haber algunos trucos para usar estructuras de datos menos gravadas en Cython. Por ejemplo, esta página ( http://wiki.cython.org/tutorials/numpy ) muestra cómo hacer arreglos numpy muy rápido en Cython predefiniendo el tamaño y los tipos de la matriz ND.

Pregunta: ¿Hay alguna manera de hacer algo similar con listas/dictos, por ejemplo,indicando aproximadamente cuántos elementos o pares (clave, valor) espera tener en ellos? Es decir, ¿hay una forma idiomática de convertir listas/dictados a estructuras de datos (rápidas) en Cython?

Si no, supongo que tendré que escribirlo en C++ y envolver en una importación de Cython.

Author: ramanujan, 2009-10-07

5 answers

Cython ahora tiene soporte para plantillas, y viene con declaraciones para algunos de los contenedores STL.

Véase http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html#standard-library

Aquí está el ejemplo que dan:

from libcpp.vector cimport vector

cdef vector[int] vect
cdef int i
for i in range(10):
    vect.push_back(i)
for i in range(10):
    print vect[i]
 31
Author: Sam Hartsfield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-14 17:09:26

Hacer operaciones similares en Python como en C++ a menudo puede ser más lento. list y dict se implementan muy bien, pero se obtiene una gran cantidad de sobrecarga usando objetos Python, que son más abstractos que los objetos C++ y requieren mucha más búsqueda en tiempo de ejecución.

Por cierto, std::vector se implementa de una manera bastante similar a list. std::map, sin embargo, en realidad se implementa de una manera que muchas operaciones son más lentas que dict a medida que su tamaño se hace grande. Para ejemplos adecuadamente grandes de cada uno, dict supera el factor constante por el cual es más lento que std::map y realmente hará operaciones como búsqueda, inserción, etc. más rápido.

Si quieres usar std::map y std::vector, nada te detiene. Tendrás que envolverlos tú mismo si quieres exponerlos a Python. No se sorprenda si este envoltorio consume todo o gran parte del tiempo que esperaba ahorrar. No tengo conocimiento de ninguna herramienta que haga que esto sea automático para usted.

Hay llamadas a la API C para controlar el creación de objetos con algún detalle. Puedes decir "Haz una lista con al menos estos elementos", pero esto no mejora la complejidad general de la operación de creación y llenado de tu lista. Ciertamente no cambia mucho más tarde a medida que intenta cambiar su lista.

Mi consejo general es

  • Si desea una matriz de tamaño fijo (se habla de especificar el tamaño de una lista), en realidad puede querer algo como una matriz numpy.

  • Dudo que vayas para obtener cualquier aceleración que desee al usar std::vector sobre list para un reemplazo general en su código. Si desea usarlo detrás de las escenas, puede darle una mejora satisfactoria de tamaño y espacio (por supuesto, no lo sé sin medir, ni usted. ;) ).

  • dict en realidad hace su trabajo muy bien. Definitivamente no intentaría introducir un nuevo tipo de propósito general para su uso en Python basado en std::map, que tiene peor complejidad algorítmica en el tiempo para muchos operaciones y-al menos en algunas implementaciones-deja algunas optimizaciones al usuario que dict ya tiene.

    Si quisiera algo que funcionara un poco más como std::map, probablemente usaría una base de datos. Esto es generalmente lo que hago si las cosas que quiero almacenar en un dict (o para el caso, las cosas que almaceno en un list) se vuelven demasiado grandes para que me sienta cómodo almacenándolas en la memoria. Python tiene sqlite3 en el stdlib y controladores para todas las demás bases de datos principales disponibles.

 30
Author: Mike Graham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-23 14:58:39

C++ es rápido no solo por las declaraciones estáticas del vector y los elementos que van en él, sino crucialmente porque usando templates/genéricos se especifica que el vector solo contendrá elementos de un cierto tipo, por ejemplo, vector con tuplas de tres elementos. Cython no puede hacer esta última cosa y suena no trivial have tendría que ser forzada en tiempo de compilación, de alguna manera (typechecking en tiempo de ejecución es lo que Python ya hace). Así que ahora mismo cuando usted pop algo de un list en Cython no hay forma de saber de antemano de qué tipo es , y ponerlo en una variable mecanografiada solo agrega una comprobación de tipo, no velocidad. Esto significa que no hay manera de pasar por alto el intérprete de Python en este sentido, y me parece que es el defecto más crucial de Cython para tareas no numéricas.

La forma manual de resolver esto es subclasificar la lista/dict de python (o tal vez std::vector) con una clase cdef para un tipo específico de elemento o combinación clave-valor. Este equivaldría a lo mismo que el código que las plantillas están generando. Mientras utilice la clase resultante en código Cython, debería proporcionar una mejora.

El uso de bases de datos o arrays solo resuelve un problema diferente, porque se trata de colocar objetos arbitrarios (pero con un tipo específico, y preferiblemente una clase cdef) en contenedores.

Y std:: map no debe compararse con dict; std:: map mantiene las claves en orden porque es un árbol equilibrado, dict resuelve un otro problema. Una mejor comparación sería dict y hashtable de Google.

 9
Author: Andreas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-26 13:55:00

Puedes echar un vistazo a la norma array módulo para Python si es apropiado para su configuración de Cython. No estoy seguro ya que nunca he usado Cython.

 2
Author: Andrey Vlasovskikh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-10 03:57:11

No hay manera de obtener listas/dictados nativos de Python a la velocidad de un mapa/vector de C++ o incluso en cualquier lugar cercano. No tiene nada que ver con la asignación o la declaración de tipos, sino que paga los gastos generales del intérprete. El ejemplo que mencionas (numpy) es una extensión C y está escrito en C precisamente por esta razón.

 1
Author: Karl Guertin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-10 04:38:32