| The State of Go |
| Where we are in February 2017 |
| |
| Francesc Campoy |
| Google Developer Advocate |
| @francesc |
| campoy@golang.org |
| |
| * Time flies |
| |
| Go 1.6 is one year old (Happy Birthday!) |
| |
| Go 1.7 is already 6 months old! |
| |
| Go 1.8 was released on February 16th. |
| |
| .image state-of-go/img/flying.png |
| |
| * Notes |
| |
| The slides are available on [[https://go.dev/talks/2017/state-of-go.slide]] |
| |
| Most of the code examples won't run except locally and using Go 1.8. |
| |
| The playground still runs Go 1.7. |
| |
| * Agenda |
| |
| Changes since Go 1.7: |
| |
| - The Language |
| - The Standard Library |
| - The Runtime |
| - The Tooling |
| - The Community |
| |
| * Changes to the language |
| |
| * Conversion rules |
| |
| How many times have you found yourself with two types that were *almost* equal? |
| |
| Let's say you define `Person`: |
| |
| .code state-of-go/stdlib/json_old.go /type Person/,/^}/ |
| |
| And that for some reason, like JSON you also have: |
| |
| .code state-of-go/stdlib/json_old.go /var aux/,/}/ |
| |
| * Conversion rules |
| |
| In order to convert `aux` to type `Person` you needed to do: |
| |
| .code state-of-go/stdlib/json_old.go /type Person/,/}/ |
| |
| return Person{ |
| Name: aux.Name, |
| AgeYears: aux.AgeYears, |
| SSN: aux.SSN |
| } |
| |
| * Conversion rules |
| |
| Since Go 1.8 you can simply do: |
| |
| return Person(aux) |
| |
| Both types still need to have: |
| |
| - same *sequence* of fields (the order matters) |
| - corresponding fields with same type. |
| |
| * Conversion rules |
| |
| A non-constant value x can be converted to type T in any of these cases: |
| |
| - x is assignable to T. |
| - x's type and T have identical underlying types. |
| - x's type and T are unnamed pointer types and their pointer base types have identical underlying types. |
| - ... |
| |
| * Conversion rules |
| |
| A non-constant value x can be converted to type T in any of these cases: |
| |
| - x is assignable to T. |
| - *ignoring*struct*tags*, x's type and T have identical underlying types. |
| - *ignoring*struct*tags*, x's type and T are unnamed pointer types and their pointer base types have identical underlying types. |
| - ... |
| |
| * Ports to other platforms |
| |
| * Ports to other platforms |
| |
| 32-bit MIPS |
| |
| - big-endian (`linux/mips`) |
| - little-endian (`linux/mipsle`) - requires Floating Point Unit |
| |
| Go on DragonFly BSD now requires DragonFly 4.4.4+. |
| |
| Go on OpenBSD now requires OpenBSD 5.9+. |
| |
| Plan 9 is now better! |
| |
| * Ports to other platforms |
| |
| Go 1.8 supports OS X 10.8+. Likely last time we support 10.8. |
| |
| ARM: |
| |
| - Go 1.8 is the last version to support ARMv5E and ARMv6 processors. |
| |
| - Go 1.9 will require ARMv6K. Will it work on my platform? |
| |
| go tool dist -check-armv6k |
| |
| * Tools |
| |
| * Fix |
| |
| Fixes the import path `"golang.org/x/net/context"` to `"context"`. |
| |
| .code state-of-go/tools/gofix.go |
| |
| Simply run the command below: |
| |
| .play state-of-go/tools/gofix.sh /go tool/ |
| |
| Drop the `-diff` flag to rewrite the files. |
| |
| * Vet |
| |
| "Vet is stricter in some ways and looser where it previously caused false positives." |
| |
| Example of extra check: |
| |
| .play -edit state-of-go/tools/govet.go /func main/, |
| |
| `govet` detects the problem statically: |
| |
| .play state-of-go/tools/govet.sh /go vet/ |
| |
| * SSA everywhere! |
| |
| The SSA backend: |
| |
| - generates more compact and efficient code |
| - is a better platform for optimizations |
| |
| For 32-bit ARM systems this means 20-30% speed up! |
| |
| For others (where SSA was used already) gains are 0-10%. |
| |
| * SSA everywhere |
| |
| .image state-of-go/img/benchmark.png _ 800 |
| |
| * Default GOPATH |
| |
| Yay! |
| |
| When `GOPATH` is not defined, the tool will use: |
| |
| - `$HOME/go` on Unix |
| - `%USERPROFILE%\go` on Windows |
| |
| * go bug |
| |
| Easier way to create bugs including all relevant information. |
| |
| Example: |
| |
| .play state-of-go/tools/gobug.sh /go bug/ |
| |
| * Runtime |
| |
| * Detection of concurrent map accesses |
| |
| Improvement on Go 1.6. |
| |
| .play state-of-go/runtime/mapcrash.go /const/,/Wait\(\)/ |
| |
| Outputs: |
| |
| fatal error: concurrent map read and map write |
| fatal error: concurrent map writes |
| |
| * Mutex Contention Profiling |
| |
| Profile your benchmarks and the contention on your mutexes. |
| |
| go test bench=. -mutexprofile=mutex.out |
| |
| |
| Alternatively, activate contention profiling with this new method. |
| |
| runtime.SetMutexProfileFraction |
| |
| _Note_: For now `sync.RWMutex` is not profiled. |
| |
| * Mutex Contention Profiling |
| |
| Let's write a program to count how many times each factor appears from 2 to N. |
| |
| Example N = 10: |
| |
| Factorizations: |
| |
| 2: 2 |
| 3: 3 |
| 4: 2 2 |
| 5: 5 |
| 6: 2 3 |
| 7: 7 |
| 8: 2 2 2 |
| 9: 3 3 |
| 10: 2 5 |
| |
| Count: |
| |
| 2: 8 |
| 3: 4 |
| 5: 2 |
| 7: 1 |
| |
| * Mutex Contention Profiling |
| |
| Which option is better? |
| |
| Wide protected region: |
| |
| .play state-of-go/runtime/mutex/main.go /WIDE/,/Unlock/ |
| |
| Narrow protected region: |
| |
| .play state-of-go/runtime/mutex/main.go /NARROW/,/}/ |
| |
| * Benchmark |
| |
| $ go test -bench=. |
| |
| # BenchmarkNarrowSection/10-8 300000 5085 ns/op |
| # BenchmarkNarrowSection/100-8 20000 77458 ns/op |
| # BenchmarkNarrowSection/1000-8 2000 909658 ns/op |
| # BenchmarkNarrowSection/10000-8 100 21230633 ns/op |
| # |
| # BenchmarkWideSection/10-8 200000 5323 ns/op |
| # BenchmarkWideSection/100-8 10000 103228 ns/op |
| # BenchmarkWideSection/1000-8 1000 2131861 ns/op |
| # BenchmarkWideSection/10000-8 10 103575793 ns/op |
| |
| .image state-of-go/img/mutex_noprofile.png _ 1000 |
| |
| * Benchmarking with Mutex Contention |
| |
| $ go test -bench=. -mutexprofile=mutex.out |
| |
| # BenchmarkNarrowSection/10-8 300000 5464 ns/op |
| # BenchmarkNarrowSection/100-8 10000 108583 ns/op |
| # BenchmarkNarrowSection/1000-8 1000 1378379 ns/op |
| # BenchmarkNarrowSection/10000-8 100 32828827 ns/op |
| # |
| # BenchmarkWideSection/10-8 200000 7155 ns/op |
| # BenchmarkWideSection/100-8 10000 197001 ns/op |
| # BenchmarkWideSection/1000-8 300 4339571 ns/op |
| # BenchmarkWideSection/10000-8 5 303559562 ns/op |
| |
| .image state-of-go/img/mutex_profile.png _ 1000 |
| |
| * Analyzing the Mutex Contention Profile |
| |
| $ go tool pprof runtime.test mutex.out |
| Entering interactive mode (type "help" for commands) |
| (pprof) list |
| |
| 0 5.38s (flat, cum) 43.97% of Total |
| . . 34: mu.Lock() |
| . . 35: m[f]++ |
| . 5.38s 36: mu.Unlock() |
| |
| 0 6.86s (flat, cum) 56.03% of Total |
| . . 53: mu.Lock() |
| . . 54: for _, f := range factors(i) { |
| . . 55: m[f]++ |
| . . 56: } |
| . 6.86s 57: mu.Unlock() |
| |
| * So much contention ... |
| |
| * Contention by CPU |
| |
| .image state-of-go/img/mutex_procs.png _ 1000 |
| |
| * Comparing it to sequential algorithm |
| |
| .image state-of-go/img/mutex_all.png _ 1000 |
| |
| * Comparing it to sequential algorithm (zoom) |
| |
| .image state-of-go/img/mutex_all_zoom.png _ 1000 |
| |
| * Performance |
| |
| * GC history in tweets |
| |
| * go 1.5 |
| |
| .image state-of-go/img/gct1.png _ 900 |
| |
| * go 1.6 |
| |
| .image state-of-go/img/gct2.png _ 900 |
| |
| * go 1.7 |
| |
| .image state-of-go/img/gct4.png _ 900 |
| |
| * go 1.8 (beta 1) |
| |
| .image state-of-go/img/gct5.png _ 700 |
| |
| * go 1.8 (beta 1) CPU |
| |
| .image state-of-go/img/gctcpu.png _ 800 |
| |
| * defer is faster |
| |
| name old time/op new time/op delta |
| Defer-4 101ns ± 1% 66ns ± 0% -34.73% (p=0.000 n=20+20) |
| Defer10-4 93.2ns ± 1% 62.5ns ± 8% -33.02% (p=0.000 n=20+20) |
| DeferMany-4 148ns ± 3% 131ns ± 3% -11.42% (p=0.000 n=19+19) |
| |
| .image state-of-go/img/defer.png _ 500 |
| |
| * cgo is also faster! |
| |
| name old time/op new time/op delta |
| CgoNoop-8 93.5ns ± 0% 51.1ns ± 1% -45.34% (p=0.016 n=4+5) |
| |
| .image state-of-go/img/cgo.png _ 500 |
| |
| Source: [[https://dave.cheney.net/2016/11/19/go-1-8-toolchain-improvements][dave.cheney.net]] |
| |
| * Changes to the standard library |
| |
| * Sorting |
| |
| Exercise: |
| |
| Given a slice of `Person` |
| |
| var p []Person |
| |
| Print the slice sorted by name, age, and SSN. |
| |
| .code state-of-go/stdlib/sort/sort_test.go /sort.Sort/,/bySSN/ |
| |
| Easy, right? |
| |
| * Sorting |
| |
| Well, you forgot about this part. |
| |
| .code state-of-go/stdlib/sort/sort_test.go /byName/,/bySSN\) Swap/ |
| |
| * sort.Slice |
| |
| Since Go 1.8 you can simply write this: |
| |
| .code state-of-go/stdlib/sort/sort_test.go /sort\.Slice/,/SSN/ |
| |
| Also new `SliceStable` and `SliceIsSorted`. |
| |
| * Benchmark |
| |
| N=1 go test -bench=. |
| BenchmarkSortSort-8 10000000 145 ns/op |
| BenchmarkSortSlice-8 10000000 190 ns/op |
| N=10 go test -bench=. |
| BenchmarkSortSort-8 2000000 918 ns/op |
| BenchmarkSortSlice-8 1000000 1776 ns/op |
| N=100 go test -bench=. |
| BenchmarkSortSort-8 100000 16588 ns/op |
| BenchmarkSortSlice-8 50000 39035 ns/op |
| N=1000 go test -bench=. |
| BenchmarkSortSort-8 5000 320951 ns/op |
| BenchmarkSortSlice-8 3000 446677 ns/op |
| N=10000 go test -bench=. |
| BenchmarkSortSort-8 500 3644480 ns/op |
| BenchmarkSortSlice-8 300 4962263 ns/op |
| N=100000 go test -bench=. |
| BenchmarkSortSort-8 30 43573572 ns/op |
| BenchmarkSortSlice-8 20 60861706 ns/op |
| |
| .caption Benchmark ran on my MacBook Pro (8 cores), simply indicative. |
| |
| * Benchmark |
| |
| .image state-of-go/img/bench.png _ 800 |
| |
| * Benchmark (log/log) |
| |
| .image state-of-go/img/bench_log.png _ 800 |
| |
| |
| * Plugins |
| |
| Define a plugin: |
| |
| .code state-of-go/stdlib/plugin/plugin.go |
| |
| Then build it: |
| |
| go build -buildmode=plugin |
| |
| _Note_: This currently works only on Linux. |
| |
| * Plugins |
| |
| .code state-of-go/stdlib/plugin/main.go /plugin.Open/,/Hello/ |
| |
| * Plugins demo |
| |
| Demo video: [[https://twitter.com/francesc/status/827851085943566336][twitter.com/francesc]] |
| |
| Source code: [[https://github.com/campoy/golang-plugins][github.com/campoy/golang-plugins]] |
| |
| * HTTP shutdown |
| |
| Added `Shutdown` method to `http.Server`. |
| |
| Example: |
| |
| Call `Shutdown` when a signal is received: |
| |
| .code state-of-go/stdlib/shutdown.go /subscribe/,/}\(\)/ |
| |
| * HTTP shutdown |
| |
| Check why the server stopped. |
| |
| .code state-of-go/stdlib/shutdown.go /HandleFunc/,/gracefully/ |
| |
| |
| * HTTP/2 |
| |
| `http.Response` now satisfies the `http.Pusher` interface. |
| |
| type Pusher interface { |
| Push(target string, opts *PushOptions) error |
| } |
| |
| A simple example: |
| |
| .code state-of-go/stdlib/http2/http2.go /func rootHandler/,/^}/ |
| |
| * HTTP/2 |
| |
| .play state-of-go/stdlib/http2/http2.go /func main/,/^}/ |
| |
| HTTP: [[http://localhost:8080]] |
| HTTP/2: [[https://localhost:8081]] |
| |
| * HTTP/2 |
| |
| HTTP |
| |
| .image state-of-go/img/http.png _ 800 |
| |
| HTTP/2 |
| |
| .image state-of-go/img/http2.png _ 800 |
| |
| * More context support |
| |
| Since Go 1.7: |
| |
| - net |
| - net/http |
| - os/exec |
| |
| Since Go 1.8: |
| |
| - http.Server.Shutdown |
| - database/sql |
| - net.Resolver |
| |
| * A couple more changes too |
| |
| .image state-of-go/img/more.png _ 1000 |
| .caption [[https://beta.golang.org/doc/go1.8][Go 1.8 release notes]] |
| |
| * The community |
| |
| * Women Who Go |
| |
| .image state-of-go/img/wwg.png _ 800 |
| .caption 16 chapters already! [[http://www.womenwhogo.org]] |
| |
| * Go meetups |
| |
| .image state-of-go/img/meetups.png _ 900 |
| .caption Gophers all around the world! [[http://go-meetups.appspot.com]] |
| |
| * Conferences: |
| |
| - [[https://fosdem.org/2017/][FOSDEM]], right here right now! |
| - [[http://www.gophercon.in/][GopherCon India]], Feb 25-25th |
| - [[https://gophercon.com/][Gophercon Denver]], Jul 12-15th |
| - [[http://golanguk.com/][Golang UK]], August 16th-18th |
| - [[http://2017.dotgo.eu/][dotGo]], Nov 6th |
| |
| * Go 1.8 release party, February 16th |
| |
| Go 1.8 ships soon! |
| |
| Go meetups are organising to hold a [[https://github.com/golang/go/wiki/Go-1.8-release-party][release party]] on the 16th of February. |
| |
| .image state-of-go/img/party-gopher.png _ 300 |
| .caption Join the party!!! |