Monday, December 30, 2013

Writing some Go! code

This post is my notes when writing some code in Go lang. To start off, I will write a Hello World program in Go language.  See below.
package main

import "fmt"

func main(){
 messageToPrint := "Welcome to Go!"
 fmt.Printf(messageToPrint + "\n")
}

Now to run this, you can do one of the following :
go run HelloWorld.go
OR

go build HelloWorld.go
In the first case, "go run" compiles the program and runs it. It does not create an executable as such. (It could be creating a temporary executable somewhere.) The second command actually builds an executable which you can run. Go also has a tool called "gofmt" which you can run directly as gofmt or can run as
go fmt HelloWorld.go 
. The formatting tool formats your source code so that it matches the Go-defined formatting. This is a good thing as each one of us need not invent our own coding conventions. Gofmt can also be used to perform some code refactoring. In order to perform a rename variable, the following command does the trick.
gofmt -l -w -r 'messageToPrint -> mesg' ./HelloWorld.go 
The above command would rename the messageToPrint variable as mesg. In general, you pass 'pattern -> replaceWith' style of commands when using the -r option. More information on what gofmt -r can be used for is available in this presentation  

Writing a Web Server in Go!

The following code snippet shows a Web Server that is written in Go! and also shows how to write anonymous functions in Go!
package main

import (
 "fmt"
 "net/http"
)

func main() {
 fmt.Printf("Web Server will be started at port 8080\n")
        //See below for anonymous function
 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path)
 })
 http.ListenAndServe(":8080", nil)
}

Now a better way (in my opinion) to write the same code as above is shown below.
package main

import (
 "fmt"
 "net/http"
)

func main() {
 fmt.Printf("Web Server will be started at port 8080\n")
 rootHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path)
 })

 srv := http.Server{
  Handler: rootHandler,
  Addr:    ":8080",
 }

 srv.ListenAndServe()
}

In this example, we are actually creating an instance of a Http Server as opposed to the previous example where the http global helper methods were used to start the Http Web Service.

I was just curious to see how well this naive web service performs. Using apache bench, when I run 10000 requests at concurrency level of 100-700, the sample (stupid) program can serve around 5000 requests/second on my age old laptop. Just for kicks, the server in Go is atleast 5 times faster for each request as compared to the nodejs http server.

Back to Go! ..

  1. Package has to be "main" for your main program. Otherwise, it does not work.
  2. Passing -x flag to your helper commands such as "go run", "go fmt" or "go build" will display the complete output and the commands internally executed.
  3. The "go build" has all compiler optimizations enabled.