The Go Programming Language
Sydney University
March 23, 2010
Hello, world 2.0
package main
import (
"fmt"
"http"
)
func handler(c *http.Conn, r *http.Request) {
fmt.Fprintf(c, "Hello, %s.", r.URL.Path[1:])
}
func main() {
http.ListenAndServe(":8080",
http.HandlerFunc(handler))
}
Concurrent
Start a new flow of control with the go
keyword
Parallel computation is easy:
func main() {
go expensiveComputation(x, y, z)
anotherExpensiveComputation(a, b, c)
}
Roughly speaking, a goroutine is like a thread, but lighter weight:
- Goroutines have segmented stacks, and typically smaller stacks
- This requires compiler support. Goroutines can't just be a C++ library on top of a thread library
Concurrent
Let's look again at our simple parallel computation:
func main() {
go expensiveComputation(x, y, z)
anotherExpensiveComputation(a, b, c)
}
This story is incomplete:
- How do we know when the two computations are done?
- What are their values?
Concurrent
Goroutines communicate with other goroutines via channels
func computeAndSend(ch chan int, x, y, z int) {
ch <- expensiveComputation(x, y, z)
}
func main() {
ch := make(chan int)
go computeAndSend(ch, x, y, z)
v2 := anotherExpensiveComputation(a, b, c)
v1 := <-ch
fmt.Println(v1, v2)
}
Systems Language
Garbage collection has a reputation for being "slower"
We're expecting Go to be slightly slower than optimized C, but faster than Java, depending on the task. Nonetheless:
- Fast and buggy is worse than almost-as-fast and correct
- It is easier to optimize a correct program than to correct an optimized program
- Fundamentally, it's simply a trade-off we're willing to make
Memory layout can drastically affect performance. These two designs are equivalent in Go, but significantly different in Java:
type Point struct { X, Y int }
type Rect struct { P0, P1 Point }
// or ...
type Rect struct { X0, Y0, X1, Y1 int }