Bienvenidos sean a este post, una tecnica de programacion comun es intercambiar espacio por tiempo lo cual nos permite acelerar algunas funciones por medio de “memoizar” sus resultados porque si despues llamamos la funcion con el mismo argumento este reusa el resultado.

Anuncios

Por ejemplo imaginemos un servidor generico que recibe solicitudes que contienen cadenas con codigo Lua, cada vez que consigue una solicitud este ejecuta a loadstring en la cadena y despues llama a la funcion resultante, como loadstring es una funcion tan pesada y algunos de estos comandos enviados al server pueden ser bastante frecuentes, en lugar de llamar a loadstring repetidamente cada vez que recibe un comando comun como es cerrar conexion.

Anuncios

El servidor puede memoizar los resultados de loadstring por medio de una tabla auxiliar, esto nos permite que en lugar llamar primero a loadstring el servidor chequee en la tabla si la cadena informada se encuentra en la misma, si no la encuentra luego (y solo luego) el servidor llama a loadstring y despues procede a almacenarla en la tabla, podemos empacar esta conducta en la siguiente funcion:

Anuncios
local resultados = {}
function mem_loadstring(s)
	local res = resultados[s]
	if res == nil then
		res = assert(loadstring(s))
		resultados[s] = res
	end
	return res
end

Los ahorros con este esquema pueden ser enormes sin embargo esto tambien crea un desperdicio insospechado, a pesar de que algunos comandos se repitan varias veces pero muchas otros ocurren una sola vez porque gradualmente la tabla resultados acumula todos los comandos que el servidor recibe ademas de sus respectivos codigos y despues de un tiempo largo esto puede acabar con la memoria del servidor, una solucion simple para este problema son las tablas debiles, de las cuales hablamos en el post anterior, si la tabla resultados tiene valores debiles por cada ciclo de coleccion de basura todas las referencias en la tabla que no esten en uso actualmente (lo cual significa virtualmente todos) seran removidas o recolectadas , veamos como seria la modificacion:

Anuncios
local resultados = {}
setmetatable(resultados, {__mode = "v"})
function mem_loadstring(s)
... el resto del codigo como antes.

Como en realidad los indices son siempre cadenas podemos hacer esta tabla completamente debil si queremos como se ve a continuacion:

setmetatable(resultados, {__mode = "kv"})
Anuncios

El resultado neto es el mismo, la tecnica de memoizar es util tambien para asegurar la unicidad de algunos tipo de objetos, por ejemplo si tenemos un sistema que representa colores como tablas con los campos rojo, verde y azul en el mismo rango, podemos usar el siguiente codigo simple para una fabrica de colores que genera un nuevo color por cada nueva solicitud:

function crearRVA(r, v, a)
	return {rojo = r, verder = v, azul = a}
end
Anuncios

Usando esta tecnica de memoizar podemos reusar la misma tabla para el mismo color, para crear una clave unica para cada color simplemente concatenamos cada indice de color con un separador entre medio, veamos el codigo modificado:

local resultados = {}
setmetatable(resultados, {__mode = "kv" })
function crearRVA(r, v, a)
	local clave = r .. "-" .. v .. "-" .. a
	local color = resultados[clave]
	if color == nil then
		color = {rojo = r, verde = v, azul = a }
		resultados[clave] = color
	end
	return color
end
Anuncios

Una consecuencia interesante de esta implementacion es que el usuario puede comparar colores usando el operador de igualdad primitivo porque dos coexistentes colores iguales son siempre representados por la misma tabla, a pesar de que el mismo color podria ser represntado por distintas tablas en diferentes momentos porque de tiempo en tiempo un ciclo coleccionista de basura limpia la tabla resultados.

Anuncios

Sin embargo, mientras el color informado continue en uso esta no sera removido de la tabla resultados, asi que cuando un color sobrevive el tiempo suficiente para ser comparado con uno nuevo y su representacion tambien sobre el tiempo suficiente para ser reusado por el nuevo color.

Anuncios

En resumen, hoy hemos visto que es “memoizar”, que es, para que sirve, un caso simple para implementarlo, como implementarlo y como optimizarlo con una tabla debil, espero te haya sido util sigueme en Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.00