Publicidad
Publicidad

RSS GoLang

Después de escribir la anterior entrada sobre el lenguaje de programación go y de leer un comentario donde se dice que Go es bastante lento, me he decidido a realizar unos benchmarks muy sencillos.

La idea es comparar la velocidad de ejecución de la devolución del logaritmo natural de un número dado y la introducción del mismo en un mapa o hash. Obviamente, la velocidad depende en gran medida de la implementación del contenedor en cada lenguaje.

En cuanto a Go, he usado el compilador 6g basado en Inferno por que no quiero instalar una versión inestable del compilador GCC en mi Gentoo Linux y cagarla a lo grande, supuéstamente, el gccgo optimiza más el código que el 6g.

Implementación C

Vamos a empezar por la implementación en C de este sencillo benchmark. He utilizado las librerías uthash para crear al Hash, puedes encontrarlas en sourceforge

Código becnhmark.c

#include <math .h> #include "uthash.h" struct map { float id; float value; UT_hash_handle hh; }; struct map *dict = NULL; void add_data(float data_id, float data) { struct map *m; m = malloc(sizeof(struct map)); m->id = data_id; m->value = data; HASH_ADD_INT( dict, id, m ); } int main() { for (int i = 0; i < 5000000; i++) { add_data(i, log(i)); } return 0; }

Compilación

genbeta@dev $ gcc -O3 -Wall -c -fmessage-length=0 -MMD -MP -std=c99 benchmark.c gcc -lm -o cbench benchmark.o

Implementación C++

Para C++ usamos el contenedor map de la STL

Código benchmark.cpp

#include <iostream> #include <map> #include <cmath> using namespace std; int main() { map <float , float> dict; for (int i = 0; i < 5000000; i++) { dict[i] = log(i); } return 0; }

Compilación

genbeta@dev $ g++ -O3 -Wall -c -fmessage-length=0 -MMD -MP benchmark.cpp -o cppbenchmark.o g++ -o cppbench cppbenchmark.o

Implementación en C# de Mono

Los expertos en .NET C# que me perdonen pero no tengo ni idea de C# no se si este snippet está muy bien pero el caso es que funciona de maravilla, si hay algún error ruego que me corrijan.

Código benchmark.cs

using System; using System.Collections; namespace CSBenchmark { class MainClass { public static void Main (string[] args) { Hashtable dict = new Hashtable(); for (int i = 0; i < 5000000; i++) { dict.Add(i, Math.Log(i)); } } } }

Compilación

genbeta@dev $ /usr/bin/gmcs /noconfig "/out:./benchmark.exe" "/r:/usr/lib/mono/2.0/System.dll" /nologo /warn:4 /debug:+ /debug:full /optimize- /codepage:utf8 /platform:x86 "/define:DEBUG" /t:exe "./benchmark.cs"

Implementación en Python

Esta sea seguramente la más sencilla de todas :)

Código benchmark.py

import math d = {} for i in range(1, 5000000): d[i] = math.log(i)

Implementación en Go

Esta también es muy sencilla, está más o menos a la par con C++

Código benchmark.go

package main import "math" func main() { m := make(map[float64] float64) var i float64 = 1 for ; i < 5000000.; i++ { m[i] = math.Log(i) } }

Compilación

genbeta@dev $ 6g benchmark.go && 6l benchmark.6 && mv 6.out gobench

Benchmarking

Para la ejecución de los benchmarks utilizo el comando time de GNU sobre el siguiente sistema:Sistema Operativo: Gentoo LinuxArquitectura: x86_64Procesador: Intel® Core™ i7 CPU @ 2.80GHzVelocidad RAM: 1666

LenguajeTiempo UsuarioTiempo SistemaTiempo RealUso de CPUUso de RamCambios de ContextoC1.90s0.27s2.19s99%1826704kB1C++4.07s0.14s4.24s99%941808kB1C#1.72s0.29s2.01s131%2032176kB1155Python CPython 2.7.23.43s0.37s3.86s99%2101312kB1Python PyPy-c1.51.57s0.33s2.70s99%2442032kB280Go2.76s0.16s2.93s99%1044304kB1

Es destacable como C# es el más rápido con 2.01, no tengo ni idea de si eso es así por la implementación de Mono, del lenguaje en si, o si es que no he hecho bien el benchmark en C# pero lo cierto es que estoy gratamente impresionado. Le sigue muy de cerca C con 2.19s, después la implementación PyPy de Python 2.7 con 2.70, tras él le toca el turno a Go con 2.93, la implementación de CPython 2.7 le sigue con 3.86 y muy tristemente el último lugar lo ocupa C++ con un 4.24

También podemos apreciar como Mono y PyPy utilizan más de un núcleo de mi procesador i7 mientras que el resto solo utilizan un núcleo al 99%.

En cuanto al consumo de memoria, C++ es el más óptimo seguido muy de cerca por Go. C# y Python —en ambas implementaciones— hacen un uso mucho mayor de recursos.

Go Profiling

Pero ojo, ese benchmark ha sido ejecutado sin utilizar profiling en Go. En Go se usan las herramientas de profiling para detectar cuellos de botella y arreglarlos mejorando el rendimiento considerablemente. El paper al que un usuario hacía referencia en el anterior post, es un benchmark sin profiling en Go y ya ha tenido su respuesta por parte de los creadores del lenguaje en el blog oficial. Vamos a utilizar profiling a ver cuanto podemos mejorar el rendimiento de nuestro snippet en Go.

Primero modificamos el código de nuestra función para añadir soporte para cpuprofiling, nuestro código quedaría así: package main import ( “math” “os” “flag” “log” “runtime/pprof” ) var cpuprofile = flag.String(“cpuprofile”, “”, “write cpu profile to file”) func main() { flag.Parse() if *cpuprofile != “” { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } m := make(map[float64] float64)

var i float64 = 1 for ; i < 5000000.; i++ { m[i] = math.Log(i) } }

Ahora podemos ejecutar el snippet con el parámetro cpuprofile y depurarlo con gopprof: ./gobench -cpuprofile=gobench.prof gopprof gobench gobench.prof Welcome to pprof! For help, type 'help'. (pprof) top10 Total: 290 samples 149 51.4% 51.4% 224 77.2% hash_insert_internal 32 11.0% 62.4% 32 11.0% math.Log 17 5.9% 68.3% 17 5.9% runtime.mcpy 17 5.9% 74.1% 17 5.9% runtime.memmove 16 5.5% 79.7% 16 5.5% memhash 13 4.5% 84.1% 13 4.5% runtime.memclr 13 4.5% 88.6% 13 4.5% scanblock 8 2.8% 91.4% 250 86.2% runtime.mapassign 5 1.7% 93.1% 8 2.8% MHeap_AllocLocked 5 1.7% 94.8% 5 1.7% memwordcopy (pprof)

Podemos ver que la aplicación ocupa la mayoría de los ciclos de la CPU y el tiempo de ejecución en introducir valores en el map. El depurado de aplicaciones desarrolladas en Go con gopprof va mucho más allá de la intención de esta entrada, pero comprobando los listados del código y los samples empleados en cada línea podemos saber que el cuello de botella esta en la línea m[i] = math.Log(i) que acumula 285 de los 290 samples de la ejecución.

Queda claro que el uso de un map para esta benchmark no es nada óptimo y podríamos utilizar un slice para almacenar los datos. Si editamos el archivo y comentamos la linea /*m := make(map[float64] float64)*/ y usamos un slice en lugar de un map var p [5000000]float64; m := make([]float64, len(p)) y volvemos a generar un archivo .prof y depuramos: Welcome to pprof! For help, type 'help'. (pprof) top10 -cum Total: 25 samples 7 28.0% 28.0% 25 100.0% main.main 0 0.0% 28.0% 25 100.0% runtime.initdone 0 0.0% 28.0% 25 100.0% runtime.mainstart 18 72.0% 100.0% 18 72.0% math.Log (pprof)

Comprobamos que ahora la práctica totalidad del tiempo está dedicada a la función que devuelve el logaritmo natural de i y ya no hay ningún cuello de botella. Vamos a eliminar el código que introduce la funcionalidad de depurado comentándolo y pasemos el benchmark otra vez.

LenguajeTiempo UsuarioTiempo SistemaTiempo RealUso de CPUUso de RamCambios de ContextoGo0.22s0.01s0.24s99%314512kB1

Ouch! Una mejoría notable. Pero seamos justos, vamos a cambiar el hash en la implementación de C por un simple array y convertir el benchmark en simplemente calcular el logaritmo natural de i e introducir el valor en un array.

LenguajeTiempo UsuarioTiempo SistemaTiempo RealUso de CPUUso de RamCambios de ContextoC0.31s0.00s0.31s99%1824kB1Go0.22s0.01s0.24s99%314512kB1

En este caso, Go es incluso más rápido que C devolviendo el logaritmo natural de i.

Conclusión

Parece que el tipo map no está muy fino en Go, aún así, la velocidad y eficiencia del lenguaje está entre C y C++. En este caso, no podemos hacer nada cien por cien legítimo por eliminar el cuello de botella por que es parte específica del test que hemos realizado. No se si hay que esperar cuatro años como he leído por ahí a que el lenguaje esté más maduro o no. Está claro que aún le falta madurez y necesita unas cuantas implementaciones en sistemas para poder mejorar. Lo que si que se es que yo al menos le voy a seguir la pista, y más ahora que está disponible en Google App Engine y es más eficiente que Python y Java.

Más en Genbeta Dev | Introducción al lenguaje de programación Go

Con Go 1.4 ya es posible desarrollar aplicaciones Android

10 Comentarios
Con Go 1.4 ya es posible desarrollar aplicaciones Android

Durante un tiempo, sobre todo desde el anuncio de Swift por parte de Apple, muchos pensamos sin casi pruebas que Go podría convertirse en "ese lenguaje” perfecto para Android. Poco a poco y sin demasiado ruido mediático vemos que ese acercamiento entre parte de la comunidad de Go y Android empieza a dar sus frutos. Hace unas semanas se anunció la disponibilidad de Go 1.4. Entre las mejoras del lenguajes y sus principales características, ahora los desarrolladores Android podrán programar aplicaciones sencillas usando Go.

Android podría ayudar al crecimiento como lenguaje y a la popularidad de Go. En su día fue Java el que impulsó la plataforma Android, ahora mucho más maduro busca la inclusión de un nuevo lenguaje que aporte la simplicidad a la hora de desarrollar en Android. Siguiendo la estela de Android Studio como IDE le podría seguir Go como lenguaje nativo.

Leer más »

Desarrollando una "modern web app" usando Go, TDD, REST y AngularJS

Comentar
Desarrollando una "modern web app" usando Go, TDD, REST y AngularJS

Reseñamos un buen ejemplo preparado por Francesc Campoy en una de sus charlas sobre el lenguaje Go que está llevando a cabo. Se trata de desarrollar una modern web app usando Go, TDD, REST y AngularJS. El propósito de este proyecto es mostrar como algunas técnicas pueden ser aplicadas programando en Go.

Desde que hace unos meses pudimos asistir a una de sus charlas en los distintos GDGs de España, sentimos más curiosidad por conocer las posibilidades que ofrece este potente lenguaje.

Gracias a este ejemplo podremos combinar Go construyendo un API REST, desplegando en App Engine y creando una interfaz de usuario rica con AngularJS. Siguiendo paso a paso las construcción orientado a test usando TDD.

Vía | Francesc Campoy Más información | Github ejemplo, sliders

Leer más »
Publicidad

Empezar a aprender Go (golang)

28 Comentarios
Empezar a aprender Go (golang)

El lenguaje de programación Go fue lanzado en Noviembre 2009, desarrollado e ideado por Google. Durante este tiempo fuera del hype inicial ha surgido un moderado interés por aprender más sobre este “desconocido” lenguaje a la sombra aún de otros lenguajes ampliamente usados como Java, C++, C# o Python (aunque no quiero compararlos técnicamente con ellos).

Go es un lenguaje moderno, por lo que bebe de lo mejor de muchos lenguajes. Combina una sintaxis parecida a C con las características y facilidad de lenguajes dinámicos como Python. Lenguajes como C++, Java o C# son más pesado o voluminosos. En cambio, GO acierta con una sintaxis clara y concisa.Podéis leer la introducción a algunos conceptos sobre Go que hicimos hace un tiempo.

Leer más »

Benchmark entre C, C++, C#, Python y Go

43 Comentarios
Benchmark entre C, C++, C#, Python y Go

addEventListener('load', function (event) { prettyPrint() }, false);

Después de escribir la anterior entrada sobre el lenguaje de programación go y de leer un comentario donde se dice que Go es bastante lento, me he decidido a realizar unos benchmarks muy sencillos.

La idea es comparar la velocidad de ejecución de la devolución del logaritmo natural de un número dado y la introducción del mismo en un mapa o hash. Obviamente, la velocidad depende en gran medida de la implementación del contenedor en cada lenguaje.

En cuanto a Go, he usado el compilador 6g basado en Inferno por que no quiero instalar una versión inestable del compilador GCC en mi Gentoo Linux y cagarla a lo grande, supuéstamente, el gccgo optimiza más el código que el 6g.

Leer más »

Introducción al lenguaje de programación Go

25 Comentarios
Introducción al lenguaje de programación Go

addEventListener('load', function (event) { prettyPrint() }, false);


Para no perder la costumbre, hoy voy a hacer otro artículo de introducción. Está vez no va a ser de HTML5 ni de CSS3 o Python ni otro lenguaje dinámico. Hoy voy a hacer una introducción al lenguaje de programación Go que es un lenguaje compilado.

Go es un nuevo lenguaje de programación para sistemas lanzado por la todopoderosa Google en Noviembre del 2009. Aunque empezó a ser desarrollado en Septiembre del 2007 por Robert Griesemer, Rob Pike y Ken Thompson.

Go es un lenguaje de programación compilado, concurrente, imperativo, estructurado, no orientado a objetos —de una manera bastante especial— y con recolector de basura que de momento está soportado en diferentes tipos de sistemas UNIX, incluidos Linux, FreeBSD y Mac OS X. También está disponible en Plan 9 puesto que parte del compilador está basado en un trabajo previo sobre el sistema operativo Inferno. Las arquitecturas soportadas son i386, amd64 y ARM[1]. Existe un port no oficial a Microsoft Windows pero es bastante inestable. Actualmente se está trabajando para llevarlo al sistema operativo de Microsoft.

Leer más »
Publicidad