"Serializar" objetos comprimiéndolos antes para ahorrar espacio y los problemas que podremos tener

Esta pregunta surgió el otro día en uno de mis cursos on-line de campusMVP y la verdad es que es bastante interesante, no tanto porque sea especialmente difícil de hacer, si no por las implicaciones que tiene su aplicación en la práctica.


La idea está muy bien: dado que estoy almacenando objetos de mi programa en disco (o enviándolos a través de la red), si los comprimo debería ahorrar espacio en disco y/o ancho de banda. De hecho, la idea es tan buena que en ASP.NET 4.0 una de las novedades es que el almacenamiento de sesión fuera de proceso (es decir, cuando guardamos la sesión en un servidor de estado remoto o en un SQL Server), tiene una nueva opción para permitir la compresión de los datos antes de enviarlos para su almacenamiento o recuperación de sesión. Esto es muy útil para sitios web que quieren acelerar la transferencia de información en una granja de servidores, pero tiene la contrapartida de que los procesadores estarán más cargados debido a las operacioens de compresión y descompresión.


Antes de entrar en detalles sobre si esto es realmente tan bueno como parece, vamos a ver cómo podríamos implementarlo de manera sencilla con nuestro propio código.


El código de seriación (es la palabra adecuada en español, frente al más comñun «serialización» que es una adaptación del término anglosajón) sería este:

public static void SeriaYComprime(object obj, string arch) {
using(FileStream fs = new FileStream(arch, FileMode.OpenOrCreate, FileAccess.Write)) {
using (GZipStream zs = new GZipStream(fs, CompressionMode.Compress, true)) {
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(zs, obj);
}
}
}

A este método se le pasa el objeto que queremos seriar y una ruta en disco para almacenarlo y seria el objeto para almacenarlo en formato binario, usando un BinaryStream y un GZipStream por debajo para conseguir la compresión. Muy sencillo.


Por supuesto, en lugar de almacenar a disco podríamos almacenar a memoria con un MemoryStream o a cualquier otra ubicación, pero el código sería prácticamente igual.


El código para conseguir la deseriación sería como este:

public static object DescomprimeYDeseria(string arch) {
using (FileStream fs = new FileStream(arch, FileMode.Open, FileAccess.Read)) {
using (GZipStream zs = new GZipStream(fs, CompressionMode.Decompress, true)) {
BinaryFormatter bf = new BinaryFormatter();
return bf.Deserialize(zs);
}
}
}

Que es el proceso inverso al que hicimos antes, es decir, se indica el archivo, y éste se lee usando un formateador binario que usa a su vez un GZipStream por debajo en modo descompresión.


Si ahora tenemos una clase «serializable» cualquiera, por ejemplo esta:

[Serializable]
public class PruebaClaseSeriable
{
public string Propiedad1 {get; set;}
public int Propiedad2 {get; set;}
public long Propiedad3 {get; set;}
}

y escribimos esto:

PruebaClaseSeriable pcs = new PruebaClaseSeriable();
pcs.Propiedad1 = «Hola»;
pcs.Propiedad2 = 2;
pcs.Propiedad3 = 3;

SeriaYComprime(pcs, @»D:PruebaCompr.bin»);


Obtendremos un archivo «pruebaCompr.bin» en la raíz de la unidad D: con el estado completo del objeto. Este archivo lo podemos usar cuando queramos para recrear de nuevo el objeto en memoria simplemente llamando al otro método complementario:

PruebaClaseSeriable pcs2 = (PruebaClaseSeriable) DescomprimeYDeseria(@»D:PruebaCompr.bin»);

Listo. Tendríamos el objeto pcs2 con un estado idéntico al que teníamos anteriormente, aunque se reconstruya días más tarde o en una máquina diferente (esa es la idea de la seriación, o como dicen los modernos que trabajan con SOA, la idea de la deshidratación/hidratación).


En este archivo ZIP (3,56 KB) puedes descargarte el código de ejemplo e incluye también una versión sin compresión de los métodos de seriación/deseriación de objetos.


El efecto conseguido puede ser el contrario


Todo esto está genial y funciona a las mil maravillas. Sin embargo seriemos el mismo objeto anterior con y sin compresión y examinemos más de cerca los dos archivos generados.


El que no lleva compresión ocupa 229 bytes, y el que está comprimido pesa ¡294 bytes!
WTF? ¿Cómo es posible? ¡El comprimido ocupa más!.


En efecto, esto es así ya que la compresión no viene sola sino que trae una serie de elementos previos, en forma de cabecera de archivo, para poder hacer posteriormente la descompresión. Y estos elementos de la cabecera ocupan un cierto espacio (algo más de 100 bytes). Por lo tanto en este caso la compresión obtenida es mínima y encima tenemos la cabecera, por lo que al final acabamos con un archivo mucho mayor 🙁


Probemos a sustituir el lacónico «Hola» de la Propiedad1 del objeto por los cuatros primeros párrafos de «El Quijote», que son 5.046 caracteres (está incluido en el ejemplo descargable anterior).
Ahora el seriado sin compresión ocupa 5.400 bytes y el comprimido 2.968 byes, es decir, ahora sí que hemos ganado mucho. En concreto el comprimido ocupa sólo el 55% de lo que ocupaba el que no lleva compresión. No está mal.


Conclusión


La compresión a la hora de seriar objetos para transportarlos o almacenarlos puede estar bien si dichos objetos contienen muchos datos, pero en objetos pequeños con pocos miembros y poca información será contraproducente. Además en ambos casos tendremos una mayor demanda del procesador por lo que si esto es importante para nosotros debemos tenerlo en cuenta. Puede ser muy útil la compresión para seriar objetos grandes y, sobre todo colecciones o matrices de múltiples objetos pequeños, que será más comun.


Espero que el tema te haya resultado interesante y le puedas sacar partido en la práctica.

Cambiar la posición de los botones del título en Ubuntu 10.04 Lucid Lynx

Lo sé. No es habitual ni mucho menos que yo escriba algo sobre Linux en mi blog, siendo un «Tipo Windows» total. Pero para criticar hay que conocer y, sí, uso Linux con cierta frecuencia para poder conocerlo mejor. Ubuntu es sin duda la distribución que más pinta tiene de llegar a ser adoptada por el usuario promedio no empresarial, pues es muy sencilla de instalar y usar. Si usas Ubuntu el mes pasado te habrá saltado un aviso para que te actualizaras a la versión 10.04 Lucid Lynx, que es su última encarnación.


La primera cosa que llama la atención es que se han decidido por unos botones para la barra de títulos de las ventanas muy estilo Mac: ubicados a la izquierda, como se muestra en esta captura:



Si eres como yo, acostumbrado a Windows y otros sistemas con los menús a la derecha te gustará poder cambiarlas a esta posición. Pues ahora te explico cómo hacerlo.


Lo primero es ejecutar el editor de configuraciones del sistema. Para ello pulsa ALT+F2, y en la ventana que aparece escribe el comando gconf-editor, como en esta figura:



En la ventana que se abre navega, usando el árbol de la izquierda, hasta el nodo /apps/metacity/general. Una vez allí busca en el panel de la derecha el ajuste «button_layout»:



Tal y como se explica en la parte inferior podemos construir la distribución del menú tal y como deseemos simplemente usando los nombres de cada botón separados por comas, así como el símbolo de dos puntos para indicar la separación entre parte izquierda y derecha, y «spacer» para meter separaciones entre ellos.


Así, cambia el valor por defecto y pon, por ejemplo:


«:minimize,maximize,close»


y te quedará todo alineado a la derecha, como en Windows. En la figura ya se ve el ajuste aplicado:



Si además quieres tener (como es lógico, en mi opinión) el menú de sistema con órdenes especiales para la ventana, como en Windows, puedes escribir:


«menu:minimize,maximize,close»


y te aparecerá un circulito a la izquierda que es el menú de sistema de la ventana. Ahora ya está todo como en las versiones anteriores de Ubuntu y como en Windows y, si no eres usuario habitual de Mac te sentirás mucho más cómodo.


La verdad es que es una pena que este tipo de ajustes no se puedan hacer nativamente en Windows, pues darían mucho juego en la personalización del sistema y, como es sabido, aunque el sistema soporta skins lo cierto es que no se han popularizado al no existir herramientas apropiadas y no haber liberado Microsoft tampoco nada interesante al respecto.


Si usas también Ubuntu espero que esto te resulte útil. ¡Cuidadín con lo que tocas en el configurador! que te puedes cargar el sistema 😉

El próximo viernes estaré en B-Web

Lo sé. Últimamente no he tenido tiempo de escribir demasiado «con chicha técnica», pero es que llevo un mes de lo más ajetreado como podréis observar aunque sólo sea por todas las charlas y conferencias que llevo últimamente (y eso es la punta del iceberg). En breve espero retomar y escribir muchas ideas que tengo en el teclado.


Este es mi blog técnico, así que a alguno le puede chocar verme en otros ámbitos, pero en realidad también tengo otra faceta profesional bastante intensa en el mundo «marketiniano» e imparto charlas y conferencias, y escribo bastante sobre temas empresariales y de marketing. Por ejemplo la que me ocupa hoy… Pero no por ello quiere decir que no sea de interés para los visitantes habituales, ya que generalmente los temas que trato son horizontales, es decir, valen para cualquier empresa, sobre todo PYMEs.


En esta ocasión posteo para comentar que el próximo viernes, día 28, estaré como ponente en el «1er Encuentro Profesional B-Web» en A Coruña. El subtítulo del evento «Business, marketing, estrategias y nuevas oportunodades en Internet» ya dice mucho sobre de qué va el mismo.


En el enlace anterior podéis ver el programa. Yo voy a las 13:00, y hablaré sobre «El fenómeno gratis en Internet. Desafíos, oportunidades y casos prácticos».


Una de las principales tendencias del sector, y probablemente una de las que más nos va a influir en el futuro, no es tecnológica sino cultural: la idea de que todos los bienes digitales deben ser gratuitos. Podemos discutir sobre si es justo o no, pero es una realidad ineludible. Así, sectores tradicionales enteros como el audiovisual o los periódicos han visto como sus cimientos se tambalean. Pero más allá de estos efectos obvios, esta tendencia impactará enormemente a todos los negocios relacionados con los contenidos y los servicios digitales. Como todo cambio de calado, supone una gravísima amenaza pero también está lleno de grandes oportunidades. En esta ponencia hablaré sobre este fenómeno, qué se puede hacer y cómo algunos ya le están sacando partido.


También estarán en este evento hablando: Enrique Dans, Rubén Bastón, Nicolás Castro, Daniel Seijo, Juan Carlos López y Pere Rosales. en las mesas redondas de la tarde habrá mucha gente interesante también.


El precio de la inscripción es de 150 €. No te quedes sin plaza.


Toda la información en la web de B-Web y en este Flyer.


¡Ah! y después, por la noche, el 5º Lacon Network: networking a tope con la gente más interesante del sector en Galicia.

Mi próxima charla on-line: Novedades de ASP.NET 4.0 – Web Forms

Webcast MSDN: Novedades de ASP.NET  4.0 - WebFormsEl próximo martes día 18, a las 19:30 hora española estaré con la gente de SecondNUG hablando on-line sobre las novedades de ASP.NET WebForms.


Aunque Microsoft empieza a apostar fuerte por ASP.NET MVC (y que duda cabe que es una gran tecnología), ASP.NET Web Forms sigue siendo la tecnología más extendida por derecho propio. ASP.NET 4.0 es su última encarnación y ofrece también interesantes novedades, sobre todo en la parte de AJAX y Dynamic Data. En este evento veremos las principales novedades y cambios introducidos en ASP.NET 4.0.


Para sacarle el mayor partido se  precisa un buen conocimiento previo de esta tecnología.


Webcast MSDN: Novedades de ASP.NET  4.0 - WebForms


Apúntate gratis aquí: Webcast MSDN: Novedades de ASP.NET 4.0 – WebForms


¡Nos vemos por allí!

Por qué debería importarte la programación paralela

De este tema ya había hablado en una ocasión en este blog (o más bien en su blog gemelo), y lo cierto es que levantó bastante polémica.


Cuando hablo con alguna gente acerca de las novedades de Visual Studio 2010 y sale lo de las mejoras para la programación en paralelo, mucha gente lo ve como una mera anécdota, algo que no va con ellos en absoluto. Si bien es cierto que muchas aplicaciones que se hacen, como las de gestión por ejemplo, no suelen tener que sacarle partido, no es menos cierto que en muchas circunstancias nuestras aplicaciones deben poder sacarle el máximo rendimiento al hardware del que disponemos.


Desde hace unos años lo más habitual en cualquier ordenador corriente es que disponga de un procesador con al menos dos núcleos. En servidores o máquinas destinadas a tareas más demandantes es muy frecuente que haya varios procesadores con al menos cuatro núcleos. La tendencia es que cada vez haya más núcleos en los procesadores, ya no sólo por rendimiento sino por las ventajas en cuanto a ahorro de energía, temperatura y las limitaciones existentes en cuanto a aumentar la velocidad de frecuencia de reloj. Esto implica que casi cualquier aplicación pueda trabajar en entornos con múltiples núcleos, lo que hace realmente importante sacarle partido a la programación multi-subproceso.


Anteriormente, y aquí viene lo importante, para aumentar el rendimiento de una aplicación bastaba con moverla a una máquina con un procesador más rápido. Sin embargo hoy en día esto ya no vale, pues el rendimiento se obtiene a través de sacarle partido a más núcleos y no aumentando la velocidad. Así que la conclusión es que si queremos que una aplicación llegue a ser escalable ésta debe sacar partido a múltiples hilos de ejecución y, por lo tanto, a múltiples nodos de procesamiento.


¿Se ve entonces la importancia? A mi me parece fundamental.


Este tipo de programación paralela siempre ha sido muy compleja, sobre todo a la hora de depurar aplicaciones en las que existen muchas probabilidades de generar interbloqueos o “race conditions”. Con .NET 4.0 y Visual Studio 2010 se incluyen nuevas bibliotecas, tipos y herramientas para facilitar la programación multi-núcleo, y debería ser un área de suma importancia para los programadores.


.NET 4.0 incluye lo que se ha bautizado como “Parallel Extensions” que están formadas por tres nuevos componentes:



La biblioteca de tareas paralelas (TPL, Task Parallel Library): esta biblioteca dentro del espacio de nombres System.Threading.Taks.Parallel incluye construcciones para ejecutar tareas repetitivas independientes entre sí en paralelo y de forma automática, como por ejemplo versiones paralelas de los bucles For y ForEach.
El motor de ejecución paralela de Linq (PLINQ Execution Engine): como se desprende de su nombre, se trata de una versión paralelizada de Linq to Objects, que nos permite lanzar consultas integradas en el lenguaje aprovechando la capacidad de paralelismo del sistema.
Las estructuras de datos para coordinación (CDS, Coordination data Structures): ofrece un conjunto de primitivas de sincronización y de colecciones preparadas para multisubproceso (thread-safe) que simplifican los escenarios paralelizados. Por ejemplo, tenemos diccionarios, pilas y colas thread-safe, y objetos especiales para sincronización de hilos como el SpinWait o el SpinLock.


La MSDN tiene una buena documentación sobre todo esto en: http://msdn.microsoft.com/en-us/library/dd460693.aspx.


Y tú ¿qué opinas?

Nueva versión de CassiniAqui: sirve localmente cualquier carpeta con una aplicación Web

Hace ya más de 4 años, en diciembre de 2005, creé esta pequeña pero útil herramienta para programadores llamada CassiniAqui.


Se trata de una aplicación que, una vez registrada en el sistema, añade una nueva opción al menú contextual de cada carpeta que nos permite servir sus contenidos usando el servidor Web de desarrollo de Visual Studio:



Esto resulta muy útil a la hora de probar aplicaciones Web sin tener que abrir Visual Studio, para poder jugar con ellas de forma ligera en local.


El servidor de desarrollo que viene con cualquier versión de Visual Studio es una versión modificada del conocido servidor Web Open Source llamado Cassini, de ahí el nombre de la herramienta.


Novedades de esta versión


Esta versión de CassiniAqui lleva el número 4.0 para hacerlo coincidir con el de la plataforma .NET. Lo he escrito con Visual Studio 2010 y C#, pero lo he compilado con la versión 2.0 del framework, por lo que puede ser utilizado aunque tengamos instaladas versiones más antiguas del entorno de desarrollo.


Entre las novedades de esta versión cabe destacar:



· Soporte para Visual Studio 2005, Visual Studio 2008 y Visual Studio 2010.
· Soporte de versiones de 32 y 64 bits de Windows XP/Vista/7. Es diferente la forma de localizar el servidor en los sistemas x64 y en x86.
· Posibilidad de que el servidor ejecute la versión 2.0 o la 4.0 del framework gracias al parámetro “-v:” o “/v:”. De este modo podemos lanzar la más adecuada para la aplicación web que estamos probando (tienen cosas incompatibles, como la composición del web.config, por ejemplo). Por defecto lanzará siempre la versión más moderna disponible del framework. Así si tenemos VS2010 lanzará la 4.0, pero si tenemos una versión anterior de Visual Studio lanzará la 2.0.
· Posibilidad de elegir un puerto estático para el servidor en lugar de uno aleatorio, con el parámetro “-p:” o “/p:”.


Descarga e Instalación


Puedes obtener el programa descargando este archivo: CassiniAqui_4_0.zip (14 KB).


Dentro del ZIP encontrarás un ejecutable y un archivo .reg. Descomprime en cualquier carpeta de tu disco duro y haz lo siguiente:



1.- Copia CassiniAqui.exe a cualquier carpeta que esté en el PATH de tu máquina. Por ejemplo en C:Windows.
2.- En la primera carpeta, donde has descomprimido, haz doble click sobre el archivo .reg y acepta el mensaje de advertencia que se muestra. Esto meterá una clave en el registro que añade una nueva opción al menú contextual de las carpetas para poder servirlas con el servidor web de desarrollo (figura anterior).


Además de poder lanzar la utilidad desde este menú contextual podrás usarla también desde línea de comandos, así:



CassiniAqui.exe <ruta a la carpeta>  [-v:versión]  [-p:puerto]


El único parámetro obligatorio es la ruta a la carpeta que quieres lanzar (si tiene espacios deberás meterla entre comillas dobles).


El parámetro –v (puede ser también /v indistintamente) indica la versión del framework que quieres utilizar para servir las páginas. En este momento las soportadas son la 2.0 (válida para VS2005 y VS2008) y la 4.0 (válida para VS2010). Si tienes instalado solamente VS2010 podrás usar igualmente la versión 2.0 pues tiene soporte para ello. Por defecto, si no se indica, intentará lanzar la versión 4.0 y si no puede lanzará la 2.0.


El parámetro –p (o /p) sirve para especificar un puerto fijo para lanzar la aplicación. Esto puede ser útil por ejemplo para probar servicios Web que otras aplicaciones utilicen y que tengan un puerto concreto. Si no se especifica (opción por defecto en el menú contextual) se lanza en un puerto aleatorio entre el 1000 y el 9999.


Ejemplos:



· CassiniAqui.exe C:MisWebsPrueba1 /p:8081 –v:2.0  –> Sirve la carpeta indicada en el puerto 8081 y usando la versión 2.0 del framework
· CassiniAqui.exe C:MisWebsPrueba1 –> Sirve la carpeta usando un puerto aleatorio y la versión más alta del framework que esté disponible en el equipo.


Código fuente


El código fuente de la aplicación está disponible aquí: CassiniAqui_4_0_Source.zip (15 KB).


Puede resultarte interesante echarle un vistazo pues tiene algunos detalles dignos de mención. Por ejemplo el uso de una enumeración junto con reflexión y comprobación de valores  para poder añadir en el futuro nuevas versiones de manera sencilla (bastará con añadir un nuevo valor a la enumeración y un nuevo caso a un switch, generándose la documentación y la validación del parámetro –v de manera automática). También hay algunos otros más.


El código está comentado para facilitar su comprensión. Está generado con Visual Studio 2010 aunque si añades manualmente el archivo .cs a una versión anterior de VS podrás compilarlo sin problemas.


¡Espero que te resulte útil!