lunes, 1 de febrero de 2010

Victoria de Ruby resolviendo Fibonacci (vs Python)

Conversando rápidamente con un 'amix' en twitter (@Yaraher - Alvaro Pereyra) me dí con la sorpresa de que el rendimiento de Ruby se ha incrementado dramáticamente, así que lo sometí a una sencilla prueba comparándolo con Python: la archi conocida secuencia fibonacci.

El vídeo muestra una ventana de Terminator, dividida en 2 áreas horizontales y 4 verticales.  En la primera sección vertical se ejecuta la secuencia fibonacci empleando Python2.6, en la segunda con Python 3.1, en la tercera con Ruby 1.8 y en la cuarta con Ruby 1.9.1.





En primer lugar las tareas se ejecutan simultáneamente, luego se ejecuta cada una individualmente y así poder apreciar su rendimiento como proceso mandatorio.


Código Python

def fib(n):
 if n == 0 or n == 1:
         return n
 else:
  return fib(n-1) + fib(n-2)

for i in range(36):
 #print "n=%d => %d" % (i, fib(i))
 print ("n=",i," =>",fib(i))


Código Ruby

def fib(n)
 if n == 0 || n == 1
              n
 else
  fib(n-1) + fib(n-2)
 end
end

36.times do |i|
 puts "n=#{i} => #{fib(i)}"
end




El resultado de la prueba fue una victoria absoluta para Ruby 1.9.1 (con unos impresionantes 8.xx segundos, pero solamente cuando es el proceso principal que emplea el CPU, cuando no es así el rendimiento es similar al de Python), ambas versiones de Python van muy parejas sin mucho cambio en el rendimiento (19 y 21 segundos) y si están empleando 1.8, dejen de hacerlo: es malísimo (62 segundos)


Haskell: paralelo rendimiento funcional

En esta ocasión compartiré algo sobre Haskell, un maravilloso lenguaje de programación que sigue el paradigma funcional y que venimos empleando en algunos proyectos de la empresa (ICTEC SAC), tratando de elevar el rendimiento de nuestras aplicaciones pero sin perder esa simplicidad que Python nos ofrece; es así que daré una pequeñísima introducción al lenguaje tomando como "hilo" sus características de paralelismo, es decir el cálculo simultáneo de operaciones en diferentes núcleos de uno o varios procesadores (ideal para clusters o computación de alto rendimiento).

Programar en Haskell implica adentrarse en la programación declarativa y basada en funciones matemáticas, a diferencia de la programación imperativa (donde se encuentran la mayoría de lenguajes de programación) que es más bien procedimental y algorítmica.  De programación funcional hablaré en un artículo más adelante porque hoy, me quiero concentrar en el potencial de Haskell para los desarrolladores y particularmente en emplear los dos núcleos de mi Core2Duo a demanda.  Recuerden que empleo Ubuntu Jaunty, por lo que los procedimientos de instalación pueden ser diferentes en otras distros, pero el código es aplicable en cualquier SO.



Por qué programar en Haskell? Hay muchas razones, pero una de las mejores es el rendimiento, para ello revisen este enlace http://shootout.alioth.debian.org/u64/which-programming-languages-are-fastest.php ,sin obviar el código corto, limpio, con mayor mantenibilidad, etc.

Lo usual es que Haskell no venga integrado en nuestro SO, pero gracias a los repositorios que ofrece Ubuntu instalarlos es muy simple
    sudo apt-get install ghc6 libghc6-parallel-prof
   
Hecho esto, debemos saber que Haskell nos ofrece un intérprete interactivo y claro, un compilador.  Para acceder al intérprete interactivo lo hacemos con:
    ghci

Listo! Ya lo tenemos instalados, ahora a emplearlo y en esta ocasión he escogido la clásica secuencia fibonacci para demostrar el rendimiento de este lenguaje


    import Control.Monad
    import Text.Printf

    fib :: Int -> Int
    fib 0 = 0
    fib 1 = 1
    fib n = fib (n-1) + fib (n-2)

    main = forM_ [0..35] $ \i -> 
            printf "n=%d => %d\n" i (fib i)
       



    * Llamamos a los módulos Control.Monad y Text.Printf, el primero nos da acceso a acciones abstractas datatipadas,  mientras que el segundo al conocido printf que nos permite imprimir texto con formato
    * Definimos la función fib indicando que recibiremos un enetero (Int) y recibiremos otro (Int)
    * Dentro de fib manipulamos los datos y establecemos que n es el valor a recibir y el resultado de su operación el (valor) de retorno
    * Emplean main establecemos un bloque que puede invocar al módulo, que gracias a la función forM_ (parte de Control.Monad) nos permite iterar sobre los 35 primeros primos, cada valor va pasando al printf que como argumentos tiene la llamada al módulo fib.
    * Grabamos el archivo con extensión .hs y salimos al intérprete (fibo.hs)

Probaremos nuestro ejercicio directamente desde el intérprete Haskell, con lo cual desde el mismo directorio donde grabamos nuestro archivo lo invocamos con ghci.  Dentro de este, empleamos una comprensión de listas para invocarlo:
    ghci fibo.hs
    [fib x | x <-[0..35]]
    *Al cabo de unos segundos aparecerá una lista con la secuencia fibonacci
    *Salimos con [CTRL]+Z
   
El problema de lo que acabamos de hacer es que nos ha tomado algunos valiosos segundos y eso NO ES ACEPTABLE, tratemos -ahora- de compilar la aplicación
    ghc -o fibo fibo.hs
    *Esperamos unos momentos y ya tenemos un ejecutable listo para correr
    ./fibo
   
    *Estoy empleando la aplicación time para medir los tiempos de ejecución y consumo de CPU, lo pueden instalar con
    sudo apt-get install time
   
    *Lo empleamos así
    /usr/bin/time ./fibo
   
    *Nos presenta el resultado de los 35 números en 3.04 seg y con un consumo de CPU de 99%

Eso es rápido? Contra qué lo comparamos? Bueno, ahora lo entenderán porque voy a hacer lo mismo con un programa en Python


 def fib(n):
     if n == 0 or n == 1:
         return n
     else:
         return fib(n-1) + fib(n-2)

 for i in range(36):
     print "n=%d => %d" % (i, fib(i))


    *Lo grabamos como fibo.py y ejecutamos
    /usr/bin/time python fibo.py
   
    *El resultado se obtuvo en 18.79 seg y con un consumo de CPU de 100%
   
Ahora ya tenemos una referencia, Haskell ejecutó la aplicación compilada 6 veces más rápido que en Python, pero digamos qué hay de C?

 #include

 int main()
 {
      unsigned int i=0,j=0,sum=1,num=0;
      num=9227466;
 
      while(sum < num)
      {
         printf("%d ",sum);
         i=j;
         j=sum;
         sum=i+j;
       }
 }

   
    *Los grabamos como fibo.c,compilamos y ejecutamos
    gcc -o fibo-c fibo.c
    /usr/bin/time ./fibo-c

   
    *El resultado se obtuvo en 0.0 seg y con un consumo de CPU de 0%
   
"Pero mejor programemos en C", dirán algunos de ustedes, pero quienes desarrollamos sabemos que hacerlo así implicaría manejar engorrosos procesos que harán muy largo y lento el trabajo y es por ello que existen otros lenguajes de programación: hacer nuestra vida más simple (cuando es posible).  Ahora, tratemos de hacer algo más interesante aún: elevar el rendimiento de nuestra aplicación Haskell hasta menos de un segundo; Gracias a que tengo 2 núcleos puedo dividir las operaciones que realiza el programa para que cada uno de ellos cumpla una tarea y así acelerar el proceso.


 import Control.Monad
 import Text.Printf
 import Control.Parallel

 fib :: Int -> Int
 fib 0 = 0
 fib 1 = 1
 fib n = l `pseq` r `pseq` l+r
         where
         l = fib (n-1)
         r = fib (n-2)

 main = forM_ [0..35] $ \i -> 
         printf "n=%d => %d\n" i (fib i) 



           
    *El programa es el mismo que el original, pero se ha agregado el módulo Control.Parallel y dentro de fib n se ha invocado a la función pseq para que cada argumento pase por un proceso en cada núcleo
    *Lo grabamos como fibo-m.hs, compilamos y ejecutamos
    ghc -o fibo-m -O2 --make fibo-m.hs -threaded
    /usr/bin/time ./fibo-m
   
    *El resultado ahora es de 0.41 seg y con un consumo de CPU de 102%
   
La cosa mejoró verdad? Con Haskell podemos manejar con precisión nuestros núcleos y dividir las tareas, optimizando nuestras aplicaciones con suma facilidad, claro que al precio de mayor consumo de CPU, pero en los tiempos en que este se eleva cada día eso ya no es un problema. Los próximos días trataré de introducirlos a este maravilloso lenguaje ya que ahora se deben haber quedado expectantes con nuestras pruebas.


viernes, 29 de enero de 2010

Web.py con Apache WSGI

Seguimos con nuestra serie de contenidos instructivos para web.py y en esta ocasión veremos la manera de integrar este framework a Apache, el servidor web predilecto de internet.




- Recordemos que estamos comenzando apartir de una instalación limpia de Ubuntu 9.10, pero eso sí debidamente actualizada empleando:
    sudo apt-get update
    sudo apt-get upgrade


- Necesitamos el servidor apache y para obtenerlo podemos instalar el conjunto LAMP (Linux, Apache, MySQL y PHP) o solamente los paquetes requeridos: apache2 y el mod-wsgi
    LAMP:
    sudo tasksel install lamp-server
    *Al seleccionar este se nos pedirá una clave de administrador para MySQL y su confirmación, escoge una y apúntala
   
    BASICO:
    sudo apt-get install apache2 libapache2-mod-wsgi
   
- Activamos el módulo wsgi
    a2enmod wsgi
    *Este módulo puede estar ya activo, así que esto es sólo una medida de precaución
   
- Creamos un directorio en donde nos parezca, aunque en este caso lo haré dentro de /var/www
    sudo mkdir /var/www/webpy-app
    *También un directorio interno static
    sudo mkdir /var/www/webpy-app/static
   
- Editamos la configuración por defecto del apache2 para incluir el acceso a nuestra aplicación web.py
    sudo vim /etc/apache2/sites-available/default
    *Agregamos las siguientes líneas, mientras sean antes del tag </VirtualHost>

    #....
    WSGIScriptAlias /main /var/www/webpy-app/main.py/
    
    Alias /main/static /var/www/webpy-app/static/
    AddType text/html .py

    <Directory /var/www/webpy-app/>
            Order deny,allow
            Allow from all
    </Directory>
    #....


    *Grabamos y reiniciamos el servicio
    sudo /etc/init.d/apache2 restart
    * También podemos hacerlo con: sudo service apache2 restart

- Dentro de webpy-app copiamos o re-escribimos el archivo que empleamos en el primer post sobre web.py, pero haciendo unas pequeñas modificaciones
    sudo vim /var/www/webpy-app/main.py
    *El programa debe quedar así


import web

urls = (
  '/','index',
  '/informacion','informacion',
  )

application=web.application(urls, globals()).wsgifunc()

class index:
  def GET(self):
    return "<html><body><h1>Pagina Principal</h1><br><a href='/main/informacion'>Pagina Auxiliar</a></body></html>"

class informacion:
  def GET(self):
    return "<html><body>Pagina Secundaria<br><a href='/main'>Principal</a></body></html>"

#if __name__ == '__main__':
#  app.run()


- Abrimos el browser y accedemos a http://localhost/main
    *Ya podemos empezar a jugar con las URLs dentro de apache
   
En una siguiente entrega veremos aspectos más interesantes de web.py, como trabajar con vistas e incluso hacer un sitio web rápidamente

jueves, 28 de enero de 2010

Desarrollo web minimalístico con web.py

Web.py es un framework de desarrollo minimalístico y altamente funcional que nos permite desarrollar rápidamente aplicaciones web empleando python, por lo que comenzaré con algunos tutoriales que permitan a los interesados explorar este interesante módulo.

En el video incluído comienzo con una instalación virgen de Ubuntu Jaunty por lo que se siguen los siguientes pasos:





- Instalar el paquete python-setuptools, para así poder acceder a easy_install y e instalar diversos módulos python con simplicidad
    sudo apt-get install python-setuptools

- Empleando easy_install procedemos a instalar el módulo web.py
    sudo easy_install web.py

- Instalamos algún editor, en este caso geany (visual en gvtk) y vim (consola)
    sudo apt-get install geany vim

- Creamos un directorio en algún lugar, en este caso mi carpeta personal
    mkdir webpy-demo

- Dentro del directorio, creamos un archivo que nos permita dar inicio a nuestra aplicación: main.py
    cd webpy-demo
    vim main.py

- Presionamos la tecla (INSERT) y comenzamos a escribir el código:
 


import web

urls = (
  '/','index',
  '/informacion','informacion',
  )

app=web.application(urls, globals())

class index:
  def GET(self):
    return "<html><body><h1>Pagina Principal</h1><br><a href='informacion'>Pagina Auxiliar</a></body></html>"

class informacion:
  def GET(self):
    return "<html><body>Pagina Secundaria<br><a href='/'>Principal</a></body></html>"

if __name__ == '__main__':
  app.run()


 
    * Se invoca al módulo
    * Se define una tupla con las rutas de la aplicación
    * Se instancia al módulo
    * Se definen las clases, una por URL, empleando el método GET y retornando código HTML
    * Se accede al método run() para indicar que se inicie el servidor web integrado

- Ejecutamos la aplicación
    python main.py
    * Veremos que se inicia un servicio en el puerto 8080

- Abrimos el navegador, ponemos la dirección local seguida por el puerto y ya podemos acceder a nuestra sencilla aplicación
    http://localhost:8080
   
En unos minutos hemos desarrollado una sencilla aplicación, pero en los siguientes días exploraremos aún más las diversas potencialidades que nos ofrece web.py, incluyendo la manera de integrarlo a Apache.