2009-08-17 8 views
9

Para ahorrar espacio y la complejidad de tener que mantener la coherencia de los datos entre diferentes fuentes, estoy considerando almacenar índices de inicio/final para algunas subcadenas en lugar de almacenar las subcadenas. El truco es que, si lo hago, es posible que esté creando rebanadas TODO el tiempo. ¿Esto es algo que debe evitarse? ¿Es el operador de slice lo suficientemente rápido como para no tener que preocuparme? ¿Qué hay de la nueva sobrecarga de creación/destrucción de objetos?cuán rápido es el segmento de python


Bien, aprendí mi lección. No optimices a menos que haya un problema real que estés tratando de solucionar. (Por supuesto, esto no significa corregir el código incorrectamente innecesario, pero eso está al lado del punto ...) Además, prueba y perfil antes de llegar al desbordamiento de la pila. = D ¡Gracias a todos!

+8

¿Por qué no probarlo? Escribe una prueba simple. –

+0

Estoy de acuerdo y voté por balpha, pero siempre me pregunté qué tan rápido era la porción de Python. Lo uso todo el tiempo tan fácilmente como una simple asignación, pero estoy seguro de que es mucho más lento que eso. –

+0

-1: no hice ningún experimento de sincronización. –

Respuesta

8
  1. Lo suficientemente rápido como opuesto a qué? ¿Cómo lo haces ahora mismo? ¿Qué es exactamente lo que está almacenando, qué es exactamente lo que está recuperando? La respuesta probablemente depende mucho de esto. Lo que nos lleva a ...

  2. Medida! No discutir y analizar teóricamente; intenta y mide cuál es la forma más eficiente. Luego, decida si la posible ganancia de rendimiento justifica la refacturación de su base de datos.

Editar: que acaba de ejecutar una prueba de medición de cadena rebanar frente a las operaciones de búsqueda en un diccionario enchavetado en (start, end) tuplas. Sugiere que no hay mucha diferencia. Sin embargo, es una prueba bastante ingenua, así que tómalo con un poco de sal.

+1

El método actual es simplemente almacenar un texto, oraciones y tokens en la oración como cadenas separadas (en la base de datos) y vincular cada una a la otra. Me parece un montón de abatimiento innecesario; un texto de 2 MB termina ocupando 28mb de base de datos. De todos modos, lo que se recuperaría todo el tiempo son oraciones individuales del texto. La alternativa es dividir el texto según los índices almacenados. Pero tienes un buen punto. La medición es probablemente la mejor manera de hacerlo. = P – tehgeekmeister

+1

No subestime también la parte de decisión: si hay una compensación de rendimiento/espacio de almacenamiento (y la mayoría del tiempo lo hay), debe tener en cuenta los recursos que tiene. 28mb no es mucho si realmente necesita el tiempo de CPU, pero tiene un disco duro de terabyte a su disposición. 28 mb * es * mucho si está ejecutando un pequeño sistema integrado al que solo se accede una vez al día.Bueno, creo que todo lo que acabo de escribir se reduce a "Siempre depende" :-) – balpha

+0

@tehgeekmeister: Actualice su pregunta con estos datos adicionales. –

-1

La optimización prematura es el problema de todos los males.

Demuestrate a ti mismo que realmente tienes una necesidad de optimizar el código, luego actúa.

1

no he hecho ninguna medición o bien, pero como parece que usted ya está tomando un enfoque de C a un problema en Python, es posible que desee echar un vistazo a Python's built-in mmap library:

Memory- los objetos de archivo mapeados se comportan como ambas cadenas y como objetos de archivo. Sin embargo, a diferencia de los objetos de cuerda normales, estos son mutables. Puede usar objetos mmap en la mayoría de los lugares donde se esperan cadenas; por ejemplo, puede usar el módulo re para buscar a través de un archivo mapeado en memoria. Dado que son mutables, puede cambiar un solo carácter haciendo obj [índice] = 'a', o cambiar una subcadena al asignar a un sector: obj [i1: i2] = '...'. También puede leer y escribir datos comenzando en la posición actual del archivo, y buscar() a través del archivo en diferentes posiciones.

No estoy seguro de su pregunta si eso es exactamente lo que está buscando. Y vale la pena repetir que necesitas tomar algunas medidas. Python's timeit library es el más fácil de usar, pero también hay cProfile o hotshot, aunque hotshot corre el riesgo de ser eliminado de la biblioteca estándar tal como lo entiendo.

3

En un comentario, el OP menciona hinchazón "en la base de datos", pero no hay información con respecto a qué base de datos está hablando; a partir de la escasa información en ese comentario, parece que las secciones de cadena Python no son necesariamente lo que está involucrado, más bien, el "corte" sería realizado por el motor DB al momento de la recuperación.

Si esa es la situación real, entonces recomendaría principios generales contra el almacenamiento de información redundante en el DB - una "forma normal" (tal vez en un sentido laxo ;-) por el cual la información se almacena una sola vez y deriva la información se vuelve a calcular (o la carga en caché del motor de DB, etc. ;-) debería ser la norma, y ​​la "desnormalización" almacenando deliberadamente la información derivada como excepción y solo cuando se justifica por necesidades de rendimiento de recuperación específicas y bien medidas.

Si la referencia a "base de datos" era una dirección incorrecta ;-), o más bien usada en un sentido laxo como lo hice para "forma normal" ;-), entonces otra consideración puede aplicarse: dado que las cadenas de Python son inmutables, parecería natural no tener que hacer rebanadas copiando, sino más bien hacer que cada porción de reutilización reutilice parte del espacio de la memoria del elemento principal desde el que se va a cortar (de forma muy similar a las divisiones de matrices numpy). Sin embargo, eso actualmente no es parte del núcleo de Python. Una vez probé un parche para ese propósito, pero el problema de agregar una referencia a la secuencia grande y hacer que permanezca en la memoria solo porque una pequeña subcadena de la misma todavía se hace referencia tenía un gran significado para la adaptación de propósito general. Aún así, sería posible crear una subclase de propósito especial de cadena (y una de Unicode) para el caso en el que la cadena "principal" grande necesita permanecer en la memoria de todos modos. Actualmente, buffer hace un poco de eso, pero no se pueden invocar los métodos de cadena en un objeto buffer (sin copiarlo explícitamente a un objeto de cadena primero), por lo que solo es realmente útil para la salida y algunos casos especiales ... pero hay ningún bloqueo conceptual real contra el método de cadena agregada (dudo que se adopte en el núcleo, pero de todos modos debería ser decentemente fácil de mantener como un módulo de terceros ;-).

El valor de tal enfoque difícilmente puede ser probado sólidamente por medición, de una forma u otra - la velocidad sería muy similar a la aproximación actual de copia implícita; la ventaja vendría en términos de reducir la huella de memoria, lo que no haría que un código de Python determinado fuera más rápido, sino que permitiría que cierto programa se ejecutara en una máquina con un poco menos de RAM, o multi-tarea mejor cuando varias instancias se están utilizando al mismo tiempo en procesos separados. Ver rope para un enfoque similar pero más rico una vez experimentado en el contexto de C++ (pero tenga en cuenta que no entró en el estándar ;-).

1

¿Las rebanadas no serían efectivas porque crean copias de la cadena fuente? Esto puede o no ser un problema. Si resulta ser un problema, no sería posible simplemente implementar una "vista de cadena"; un objeto que tiene una referencia a la cadena de origen y tiene un punto de inicio y finalización. Al acceder/iterar, simplemente lee de la cadena fuente.

+0

Esta fue mi preocupación. Pero creo que todos tenían razón: no necesito optimizar aún, y si lo hiciera debería haber medido y probado antes de venir aquí. – tehgeekmeister

Cuestiones relacionadas