Merge pull request #38 from martskins/master
Add spanish translation - 'Data Changes' section
This commit is contained in:
commit
cb85034071
@ -57,3 +57,129 @@ La optimización prematura también puede afectarte al atarte a ciertas decision
|
|||||||
En la gran mayoría de casos, el tamaño y velocidad del programa no es el problema. La optimización más fácil es no hacerla. La segunda alternativa más fácil es simplemente comprar mejor hardware.
|
En la gran mayoría de casos, el tamaño y velocidad del programa no es el problema. La optimización más fácil es no hacerla. La segunda alternativa más fácil es simplemente comprar mejor hardware.
|
||||||
|
|
||||||
Cuando hayas decidido cambiar tu programa, sigue leyendo.
|
Cuando hayas decidido cambiar tu programa, sigue leyendo.
|
||||||
|
|
||||||
|
### Modificar los datos
|
||||||
|
|
||||||
|
Modificar los datos significa agregar o alterar la representación de los datos
|
||||||
|
que estas procesando. Desde el punto de vista del rendimiento, algunos de
|
||||||
|
estos acabaran cambiando la complejidad O() asociada a diferentes aspectos de
|
||||||
|
la estructura de datos.
|
||||||
|
|
||||||
|
Ideas para mejorar tu estructura de datos:
|
||||||
|
|
||||||
|
* Campos adicionales
|
||||||
|
|
||||||
|
El clásico ejemplo de esto es almacenar la longitud de una lista enlazada en un
|
||||||
|
campo en el nodo raíz. Mantenerla actualizada conlleva un poco más de trabajo,
|
||||||
|
pero consultar la longitud se convierte en un simple acceso a un campo en vez de una
|
||||||
|
búsqueda transversal con complejidad O(n). Tu estructura de datos puede presentar una
|
||||||
|
mejora similar: un poco de mantenimiento en algunas operaciones a cambio de
|
||||||
|
mejorar el rendimiento en un caso de uso común.
|
||||||
|
|
||||||
|
De manera similar, almacenar punteros a nodos frecuentemente utilizados en vez
|
||||||
|
de realizar búsquedas adicionales. Esto cubre cosas como el link "hacia atrás"
|
||||||
|
en una lista doblemente enlazada para hacer que la eliminación de nodos tenga una complejidad O(1).
|
||||||
|
Algunas listas de salto guardan un "puntero de búsqueda", donde almacenas un
|
||||||
|
puntero a donde recientemente estuviste en tu estructura de datos, bajo la
|
||||||
|
suposición de que es un buen punto de partida para la siguiente operación.
|
||||||
|
|
||||||
|
* Índices de búsqueda adicionales
|
||||||
|
|
||||||
|
La mayoría de las estructuras de datos están diseñadas para un único tipo de
|
||||||
|
consulta. Si necesitas dos tipos de consultas, disponer de una "vista"
|
||||||
|
adicional a tus datos puede ser una gran mejora. Por ejemplo, un set de
|
||||||
|
structs puede tener un ID primario (integer) que usas para buscar en un
|
||||||
|
slice, pero a veces necesitas buscar por un ID secundario (string). En lugar
|
||||||
|
de iterar sobre el slice, puedes mejorar tu estructura de datos con un mapa de
|
||||||
|
string a ID o directamente al struct en cuestión.
|
||||||
|
|
||||||
|
* Información adicional sobre los elementos
|
||||||
|
|
||||||
|
Por ejemplo, mantener un filtro de Bloom de todos los elementos que has
|
||||||
|
insertado puede permitirte retornar rápidamente "sin coincidencias" a las
|
||||||
|
búsquedas. Estos necesitan ser pequeños y rápidos para no abrumar el resto de
|
||||||
|
la estructura de datos. (Si una búsqueda en tu estructura de datos principal
|
||||||
|
es barata, el costo del filtro de Bloom superará cualquier ahorro.)
|
||||||
|
|
||||||
|
* Si las búsquedas son costosas, agrega una cache
|
||||||
|
|
||||||
|
A mayor escala, una cache interna o externa (como memcache) puede ayudar.
|
||||||
|
Puede ser excesivo para una única estructura de datos. Hablaremos más sobre
|
||||||
|
caches más adelante.
|
||||||
|
|
||||||
|
Este tipo de cambios son útiles cuando los datos que necesitan son baratos de
|
||||||
|
almacenar y fáciles de mantener actualizados.
|
||||||
|
|
||||||
|
Estos son todos ejemplos claros de "realizar menos trabajo" a nivel de
|
||||||
|
la estructura de datos. Todos cuestan espacio. La mayoría de las veces, si estás
|
||||||
|
optimizando para CPU, tu programa usará más memoria. Se trata del clásico [space-time trade-off](https://en.wikipedia.org/wiki/Space%E2%80%93time_tradeoff).
|
||||||
|
|
||||||
|
Si tu programa utiliza demasiada memoria, también es posible ir por el otro
|
||||||
|
camino. Reduce el uso de espacio a cambio de una mayor carga computacional. En
|
||||||
|
lugar de almacenar cosas, calcúlalas cada vez. También puedes comprimir los datos
|
||||||
|
en memoria y descomprimirlos cuando los necesites.
|
||||||
|
|
||||||
|
[Small Memory Software](http://smallmemory.com/book.html) es un libro disponible
|
||||||
|
online que cubre técnicas para reducir el espacio utilizado por tus programas.
|
||||||
|
Aunque fue originalmente escrito dirigído a desarrolladores de sistemas
|
||||||
|
embebidos, sus ideas son aplicables para programas en hardware moderno que
|
||||||
|
manejen gran cantidad de datos.
|
||||||
|
|
||||||
|
* Reorganiza tus datos
|
||||||
|
|
||||||
|
Elimina el padding. Remueve campos extra. Utiliza tipos de datos mas pequeños.
|
||||||
|
|
||||||
|
* Cambia a una estructura de datos más lenta
|
||||||
|
|
||||||
|
Estructuras de datos más simples frecuentemente presentan menores
|
||||||
|
requerimientos de memoria. Por ejemplo, cambiar una estructura tipo arbol con
|
||||||
|
uso extensivo de punteros a un slice y búsqueda lineal.
|
||||||
|
|
||||||
|
* Compresión a medida para tus datos
|
||||||
|
|
||||||
|
Los algoritmos de compresión dependen fuertemente de qué esté siendo comprimido. Lo mejor es
|
||||||
|
elegir uno que se ajuste a tus datos. Si tienes un []byte, entonces algo como snappy, gzip, lz4,
|
||||||
|
funciona bien. Para datos de punto flotante existe go-tsz para series temporales y fpc para datos
|
||||||
|
científicos. Se ha realizado mucha investigación sobre la compresión de integers, generalmente
|
||||||
|
para la obtención de datos en motores de búsqueda. Algunos ejemplos son delta encoding y variantes
|
||||||
|
o esquemas más complejos que involucran diferencias xor codificadas con el algoritmo de Huffman.
|
||||||
|
También puedes usar tu propio algoritmo optimizado exactamente para tus datos.
|
||||||
|
|
||||||
|
¿Necesitas inspeccionar los datos o pueden permanecer comprimidos? ¿Necesitas acceso aleatorio o
|
||||||
|
sólo streaming? Si necesitas acceso a entradas individuales pero no quieres descomprimirlo todo,
|
||||||
|
puedes comprimir los datos en pequeños bloques y mantener un índice que indique qué rangos de
|
||||||
|
entradas hay en cada bloque. El acceso a una única entrada solo requiere consultar el
|
||||||
|
índice y descomprimir ese bloque pequeño.
|
||||||
|
|
||||||
|
Si tus datos no estan sólo en memoria, sino que vas a escribirlos a disco, ¿qué sucede con la
|
||||||
|
migración o agregár o eliminár campos?. Estarás ahora lidiando simplemente con []byte en vez de
|
||||||
|
los convenientes tipos estructurados de Go, por lo que necesitaras hacer uso del paquete unsafe
|
||||||
|
y considerar opciones de serialización.
|
||||||
|
|
||||||
|
Hablaremos más sobre la disposición de datos más adelante.
|
||||||
|
|
||||||
|
Las computadoras modernas y la jerarquía de memoria hacen que el compromiso
|
||||||
|
entre memoria/espacio sea menos claro. Es muy fácil para las tablas de búsqueda estar
|
||||||
|
"lejos" en memoria (y por lo tanto ser costosas de acceder) haciendo que sea más rápido
|
||||||
|
simplemente recalcular un valor cada vez que se necesita.
|
||||||
|
|
||||||
|
Esto también significa que el benchmarking frecuentemente mostrará mejoras que no
|
||||||
|
aparecen en producción debido a la contención de cache (e.g., tablas de
|
||||||
|
búsqueda que estan en la cache del procesador durante el benchmarking pero
|
||||||
|
que siempre son purgadas cuando son utilizadas por un sistema real.)
|
||||||
|
El [Jump Hash paper](https://arxiv.org/pdf/1406.2294.pdf) de Google de hecho
|
||||||
|
abordó esto directamente, comparando la performance de caché con y sin problemas
|
||||||
|
de contención. (Ver gráficos 4 y 5 del artículo)
|
||||||
|
|
||||||
|
TODO: how to simulate a contended cache, show incremental cost
|
||||||
|
|
||||||
|
Otro aspecto a considerar es el tiempo de transmisión de datos. Generalmente el
|
||||||
|
acceso a disco y de red es muy lento, y por lo tanto ser capaz de cargar un
|
||||||
|
bloque comprimido va a resultar en un proceso mucho más rápido incluso teniendo
|
||||||
|
en cuenta el tiempo que lleva descomprimirlo. Como siempre, realiza benchmarks.
|
||||||
|
Un formato binario generalmente va a ser mas liviano y rápido de parsear que uno
|
||||||
|
de texto, pero el coste es que no será legible para un humano.
|
||||||
|
|
||||||
|
Para la transferencia de datos, cambia a un protocol menos verboso, o
|
||||||
|
mejora el API para aceptar consultas parciales. Por ejemplo, usa una consulta
|
||||||
|
incremental en lugar de forzar a traer siempre el set de datos completo.
|
||||||
|
Loading…
Reference in New Issue
Block a user