Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go - a simple programming environment by Andrew Gerrand

Go - a simple programming environment by Andrew Gerrand

Watch the talk here: https://vimeo.com/69237265


April 23, 2013

More Decks by Railsberry

Other Decks in Technology


  1. Go at a glance Compiled Statically typed Clean syntax Simple

    type system Concurrency primitives Rich standard library Great tools Open source This talk is just a taste.
  2. go Goroutines are lightweight threads that are managed by the

    Go runtime. To run a function in a new goroutine, just put "go" before the function call. package main import ( "fmt" "time" ) func main() { go say("let's go!", 3*time.Second) go say("ho!", 2*time.Second) go say("hey!", 1*time.Second) time.Sleep(4 * time.Second) } func say(text string, delay time.Duration) { time.Sleep(delay) fmt.Println(text) } Run
  3. chan Channels are typed conduits for sychronization and communication between

    goroutines. They're a versatile and expressive means of modelling concurrent processes. But we're not going to look at them today. (There's no time!)
  4. sync Channels are great, but sometimes other concurrency mechanisms are

    a better fit. The sync package provides mutexes, condition variables, and more useful primitives. func main() { wg := new(sync.WaitGroup) wg.Add(3) go say(wg, "let's go!", 3*time.Second) go say(wg, "ho!", 2*time.Second) go say(wg, "hey!", 1*time.Second) wg.Wait() } func say(wg *sync.WaitGroup, text string, delay time.Duration) { time.Sleep(delay) fmt.Println(text) wg.Done() } Run
  5. time The time package provides Time and Duration types, for

    expressing instants in time and periods of time. It also provides a Location type for expressing time zones. And, as we've already seen, it provides functions related to sleeping. birthday, _ := time.Parse("Jan 2 2006", "Nov 10 2009") // time.Time age := time.Since(birthday) // time.Duration fmt.Printf("Go is %d days old\n", age/(time.Hour*24)) Run t := time.Now() fmt.Println(t.In(time.UTC)) home, _ := time.LoadLocation("Australia/Sydney") fmt.Println(t.In(home)) Run
  6. net/http (1/2) The net/http package provides an HTTP client. The

    client handles HTTP Keep-Alive using a pool of connections, by default. (This is configurable, of course.) func main() { r, err := http.Get("http://www.golang.org/") if err != nil { log.Fatal(err) } if r.StatusCode != http.StatusOK { log.Fatal(r.Status) } io.Copy(os.Stdout, r.Body) } Run
  7. net/http (2/2) The net/http package also provides an HTTP server.

    This is a high-performance, DoS-hardened, production-ready web server. It serves dl.google.com. func main() { http.HandleFunc("/", handler) err := http.ListenAndServe("localhost:8080", nil) if err != nil { log.Fatal(err) } } func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Hello, web") } Run
  8. html/template The html/template package provides an HTML templating system that

    automatically escapes content depending on its context. const html = ` <script>var foo = {{.Foo}};</script> <a href="{{.URL}}"> {{.Text}} </a> ` func main() { tmpl := template.Must(template.New("example").Parse(html)) data := struct { Foo string URL, Text string }{ Foo: `Some "quoted" string`, URL: `" onClick="alert('xss!');`, Text: "The <- operator is for channel sends and receives", } tmpl.Execute(os.Stdout, data) } Run
  9. flag The flag package provides a simple API for parsing

    command-line flags. Example invocation (a little different than GNU getopt): $ flag -message 'Hold on...' -delay 5m var ( message = flag.String("message", "Hello!", "what to say") delay = flag.Duration("delay", 2*time.Second, "how long to wait") ) func main() { flag.Parse() fmt.Println(*message) time.Sleep(*delay) } Run
  10. Structure The program has two parts that execute concurrently: a

    poller that continuously checks whether Go 1.1 has been tagged, and an HTTP server providing the user interface.
  11. Sharing state We must share state ("Is Go 1.1 out?")

    between the repo poller and the user interface. This global struct variable contains a sync.RWMutex and a boolean value: var state struct { sync.RWMutex yes bool // whether Go 1.1 has been tagged. } To read, take the read lock (multiple goroutines can do this simultaneously): state.RLock() yes := state.yes state.RUnlock() To write, take the write lock (only one goroutine can do this at a time): state.Lock() state.yes = true state.Unlock()
  12. Polling (1/2) When a go1.1 tag exists in the Go

    repository this URL will return a "200 OK" response: const changeURL = "https://code.google.com/p/go/source/detail?r=go1.1" The isTagged function returns true if the go1.1 tag exists. func isTagged() bool { r, err := http.Head(changeURL) if err != nil { log.Print(err) return false } return r.StatusCode == http.StatusOK }
  13. Polling (2/2) The poll function loops until isTagged returns true.

    Then it updates the state ("Go 1.1 is out!") and returns. func poll(period time.Duration) { for !isTagged() { time.Sleep(period) } state.Lock() state.yes = true state.Unlock() }
  14. Serving the user interface The handler function serves an HTTP

    request. It puts the state.yes and changeURL values into a struct, and uses the struct to render the template as the HTTP response. func handler(w http.ResponseWriter, r *http.Request) { state.RLock() data := struct { Yes bool URL string }{ Yes: state.yes, URL: changeURL, } state.RUnlock() err := tmpl.Execute(w, data) if err != nil { log.Print(err) } }
  15. The HTML user interface The tmpl variable is a template

    that provides the HTML UI. It is a global variable, so the template is parsed just once at init time. var tmpl = template.Must(template.New("root").Parse(` <!DOCTYPE html><html><body><center> <h2>Is Go 1.1 out yet?</h2> <h1> {{if .Yes}} <a href="{{.URL}}">YES!</a> {{else}} No. {{end}} </h1> </center></body></html> `))
  16. Putting it all together The main function starts polling in

    a new goroutine and sets up the web server. Some command-line flags enable run time configuration. var ( httpAddr = flag.String("http", "localhost:8080", "Listen address") pollPeriod = flag.Duration("poll", 5*time.Second, "Poll period") ) func main() { flag.Parse() go poll(*pollPeriod) http.HandleFunc("/", handler) log.Fatal(http.ListenAndServe(*httpAddr, nil)) } The whole program is just 68 lines of code.
  17. expvar (1/2) The expvar package allows you to export variables

    via an HTTP handler registered at /debug/vars (http://localhost:8080/debug/vars) . package main import ( "expvar" "log" "net/http" "time" ) func main() { count := expvar.NewInt("count") go func() { for { count.Add(1) time.Sleep(time.Second) } }() log.Fatal(http.ListenAndServe("localhost:8080", nil)) } Run
  18. expvar (1/2) var ( hitCount = expvar.NewInt("hitCount") pollCount = expvar.NewInt("pollCount")

    pollError = expvar.NewString("pollError") pollErrorCount = expvar.NewInt("pollErrorCount") ) func isTagged() bool { pollCount.Add(1) r, err := http.Head(changeURL) if err != nil { log.Print(err) pollError.Set(err.Error()) pollErrorCount.Add(1) return false } return r.StatusCode == http.StatusOK } func handler(w http.ResponseWriter, r *http.Request) { hitCount.Add(1)
  19. Stuff I didn't talk about Types and interfaces Concurrency in

    depth Packages and the build system Code formatting Testing Benchmarking and profiling Debugging Documentation
  20. Learn more about Go The Go web site golang.org (http://golang.org)

    The Go blog blog.golang.org (http://blog.golang.org) Go talks talks.golang.org (http://talks.golang.org) A Tour of Go tour.golang.org (http://tour.golang.org)