HEY! HO! LET’S GO!
11 novembre 2009, con un post dal titolo di una famosa canzone dei Ramones, Google annunciava ufficialmente la nascita di un nuovo linguaggio di programmazione open source, denominato proprio “Go”.
Il linguaggio di programmazione Go è un progetto open source di google per rendere più produttivi i programmatori. Nell’intenzione dei loro creatori, Go è conciso, espressivo, efficiente e pulito. Una volta installato, il programmatore ha subito a disposizione una ‘cassetta degli attrezzi’ ben fornita. Ad esempio solo scrivendo
$ go
ci appare l’elenco dei comandi disponibili:
build compile packages and dependencies clean remove object files and cached files doc show documentation for package or symbol env print Go environment information bug start a bug report fix update packages to use new APIs fmt gofmt (reformat) package sources generate generate Go files by processing source get download and install packages and dependencies install compile and install packages and dependencies list list packages run compile and run Go program test test packages tool run specified go tool version print Go version vet report likely mistakes in packages
Vediamo dunque che il compilatore Go che abbiamo installato comprende anche documentazione, gestore dei pacchetti, build automation, test, installer, e molto altro!
Nello scorso articolo abbiamo elencato le principali caratteristiche del linguaggio ed abbiamo installato il compilatore, provando subito il classico “Hello, World” ; ora e’ il momento di mettersi all’opera. Anzichè perdersi in lunghe descrizioni sulla sintassi, per rispettare la filosofia di Go ho pensato di preparare dei programmi didattici, commentandoli insieme così da prendere subito confidenza.
Il primo programma è molto semplice; chiunque abbia rudimenti di un altro linguaggio C-like capirà subito di cosa si tratta
package main import ( "fmt" "time" ) func scrivi(n int) { fmt.Println(n) time.Sleep(1 * time.Second) } func main() { for i := 1; i <= 10; i++ { scrivi(i) } time.Sleep(1 * time.Second) }
Vediamo rapidamente come è composto il programma: subito dopo la dichiarazione del package, abbiamo 2 direttive import, raggruppate dentro una parentesi: in questo modo diciamo a Go che abbiamo intenzione di usare alcune funzioni di queste librerie. Di seguito una dichiarazione: la funzione scrivi accetta un parametro n, di tipo intero e non restituisce alcun valore; l’unica cosa che fa è stampare a video il numero che riceve e aspettare un secondo prima di ritornare. Notiamo già alcune cose, ad esempio che in Go il tipo delle variabili va messo dopo l’identificativo, a differenza di altri linguaggi come C, C# o Java… E che finalmente non serve più mettere il punto-e-virgola alla fine di ogni istruzione! Quante volte ce lo siamo dimenticati ?
Abbiamo infine la nostra main, il cuore del programma: con un ciclo for da 1 a 10, chiamiamo 10 volte la funzione “scrivi”; al termine del ciclo il programma si ferma per un secondo di attesa e poi termina.
Salviamo il programma in un file (ad esempio contanumeri.go) e prima di lanciare il nostro programma, proviamo a digitare
$ go fmt contanumeri.go
il sorgente verrà automaticamente “formattato” , ovvero indentato con la spaziatura e le parentesi giuste per rispettare le linee guida del linguaggio. Ora compiliamo con
$ go build contanumeri.go
e lanciamo l’eseguibile risultante, per ottenere l’ovvio risultato dei numeri in fila da 1 a 10.
$ time ./contanumeri 1 2 3 4 5 6 7 8 9 10 real 0m11,006s user 0m0,004s sys 0m0,003s
Niente di sconvolgente, ma abbiamo fatto qualche passo avanti: imparare Go non è affatto difficile!
Con questo sorgente possiamo fare un esperimento interessante: prendiamo le righe con time.Sleep e le commentiamo…
package main import ( "fmt" "time" ) func scrivi(n int) { fmt.Println(n) //time.Sleep(1 * time.Second) } func main() { for i := 1; i <= 10; i++ { scrivi(i) } //time.Sleep(1 * time.Second) }
compilando il codice, avremo un messaggio di errore. Dove sta il problema ?
$ go build contanumeri.go .\contanumeri.go:5: imported and not used: "time"
Il nostro sorgente contiene infatti una direttiva “import” per usare un package, ma di fatto non lo sta usando: questo causa un errore di compilazione in Go ed e’ un comportamento voluto: in Go si vuole forzare il programmatore alla pulizia, all’essenzialità e all’efficienza del codice: un programma che include un package per non utilizzarlo non viene neppure compilato.
Ora togliamo il commento alle righe di prima e proviamo una delle caratteristiche più potenti di Go: abbiamo visto che la funzione “scrivi” è (artificialmente, nel nostro caso) piuttosto lenta: impiega ben un secondo ad essere eseguita. In tutto infatti il programma occupa il nostro pc per circa 11 secondi. Grazie a Go, possiamo lanciare in parallelo tante copie di “scrivi” che gireranno in modo indipendente; il bello è che per far questo ci basterà modificare UNA sola riga …
package main import ( "fmt" "time" ) func scrivi(n int) { fmt.Println(n) time.Sleep(1 * time.Second) } func main() { for i := 1; i <= 10; i++ { go scrivi(i) } time.Sleep(1 * time.Second) }
in pratica abbiamo aggiunto l’istruzione go prima di invocare la funzione; in questo modo ogni esecuzione della funzione “scrivi” inizia in un thread parallelo, e il programma dopo aver avviato il thread può proseguire con le istruzioni successive senza aspettare che la funzione finisca. Di fatto questo si traduce in 10 “goroutine” eseguite contemporaneamente, lo dimostra anche il nostro output che non è più così ordinato, ma notiamo che il programma ora impiega 1 secondo in totale contro gli 11 di prima!
$ go build contanumeri.go $ time ./contanumeri 5 4 2 3 8 9 6 10 1 7 real 0m1,003s user 0m0,000s sys 0m0,004s
E se volessimo invece i numeri tutti in fila ? Go mette a disposizione del programmatore un tipo speciale di oggetti, detti “channels”, per “incanalare” i dati e far comunicare tra di loro le goroutine; ma tratteremo questo costrutto in un prossimo articolo. Come al solito, prima di concludere lascio ai lettori un link per approfondire e far pratica con Go, in attesa della prossima puntata! Go By Example è un pratico tutorial passo-passo che si può seguire direttamente dal browser, e consiste in una serie di programmini di difficoltà crescente ma ben commentati riga per riga, in modo da capire ed apprendere la sintassi del linguaggio e le sue caratteristiche.