Conférence des Geeks Anonymes sur " le langage Go ", par Thomas Hayen le 23 septembre 2020.
Cette conférence est disponible en vidéo sur Youtube : https://youtu.be/AlGGneVGTJk
4. Who am I?
- Thomas Hayen
- Computer engineer ULg 2010
- Java developer since 2010
- Go developer since 2019
5. Java?
Back to 2019…
Goals:
- Event sourced architecture
- Cloud based (Docker, Kubernetes,...)
- Micro services
- database(s)
- Messaging system
6. Java?
First version
- 6 microservices just running (no clients)
- > 1Gb memory RAM
- CPU usage >5%
- Images docker +/- 150Mo /container
- Starting time +/- 2 sec container (5 sec if docker is not spawned)
7. Let’s try Go
- 6 microservices just running (no clients)
- < 20 Mb memory RAM
- CPU usage < 1%
- Images docker +/- 5Mo /container
- Starting time < 1 sec container (2 sec if docker is not spawned)
8. $ docker images
geek/go-hello latest 760ba5405773 4.78MB
geek/spring-hello latest a224fb9bc642 121MB
$ docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM %
e680f347aee5 JAVA 0.09% 200.6MiB / 23.12GiB 0.85%
3061e909e394 GO 0.00% 1.812MiB / 23.12GiB 0.01%
Docker image comparison
10. Why Go?
- Complexity required to use languages
- Processors are multi-core, most languages offered little help to program them efficiently and safely.
- Frustration with existing languages: one had to choose either efficient compilation, efficient
execution, or ease of programming
- slow builds
- uncontrolled dependencies
- each programmer using a different subset of the language
- poor program understanding (code hard to read, poorly documented, and so on)
- ...
https://talks.golang.org/2012/splash.article
11. Go Spec
- C like
- Network (web app, …)
- Multiprocessor
- Scaling (in term of dependency and build)
- Easy to use
12. What is Go?
- Designed at Google by Robert Griesemer, Rob Pike and Ken Thompson
- Compiled,
- Concurrent,
- Garbage-collected,
- Statically typed language
- Fast build
- Simple
- Great environment
14. So let’s Go - Hello world...
// create package main every program will be in package main and have a main function
package main
// import keyword is used to import "fmt" in your package
import "fmt"
// func is used to create function entry point
func main() {
hello := "Hello world"
fmt.Println(hello)
}
17. Testing
func TestMultipleInputOutput(t *testing.T) {
tests := []struct {
name string
input1, input2, expected int
}{
{name: "1+1=2", input1: 1, input2: 1, expected: 2},
{name: "5+5=10", input1: 5, input2: 5, expected: 10},
{name: "-1-0=-1", input1: -1, input2: 0, expected: 3},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
value := sum(tt.input1, tt.input2)
if value != tt.expected {
t.Errorf("%d + %d should be %d, got %d", tt.input1, tt.input2, tt.expected, value)
}
})
}
}
18. Testing
$ go test -v *
=== RUN TestMultipleInputOutput
=== RUN TestMultipleInputOutput/1+1=2
=== RUN TestMultipleInputOutput/5+5=10
=== RUN TestMultipleInputOutput/-1-0=-1
main_test.go:17: -1 + 0 should be 3, got -1
--- FAIL: TestMultipleInputOutput (0.00s)
--- PASS: TestMultipleInputOutput/1+1=2 (0.00s)
--- PASS: TestMultipleInputOutput/5+5=10 (0.00s)
--- FAIL: TestMultipleInputOutput/-1-0=-1 (0.00s)
FAIL
FAIL command-line-arguments 0.002s
FAIL
19. A more complete example
package main
import (
"fmt"
random "math/rand"
"time"
)
import "errors"
// Upper first letters are exported
var (
NonExistingError = errors.New("NonExistingError")
NonExistingError2 = errors.New("NonExistingError2")
NonExistingError3 = errors.New("NonExistingError3")
)
// Lower letters not
const (
lowerCaseLetters = "abcdefghijklmnopqrstuvwxyz"
)
20. A more complete example
func main() {
inputArray, err := generateSliceOfRandomString(10)
checkError(err)
fmt.Println(inputArray)
quicksort(inputArray, 0, len(inputArray)-1)
for i, s := range inputArray {
fmt.Println(fmt.Sprintf("At index %d, found %s", i, s))
}
}
21. A more complete example
func checkError(err error) {
if err != nil {
switch err {
case NonExistingError:
fmt.Println("This is an NonExistingError")
case NonExistingError2:
fallthrough
case NonExistingError3:
fmt.Println("This is an NonExistingError2 or 3")
default:
panic(err)
}
}
}
22. A more complete example
func generateSliceOfRandomString(size int) ([]string, error) {
startingTime := time.Now()
defer printDuration(startingTime) // defer
rand.Seed(startingTime.UnixNano())
var slice []string = make([]string, size) // slice
time.Sleep(1 * time.Second)
for i := 0; i < size; i++ {
b := make([]byte, 16)
for i := range b {
b[i] = lowerCaseLetters[random.Intn(len(lowerCaseLetters))] //Renamed in imports
}
slice[i] = string(b)
}
return slice, nil
}
func printDuration(startingTime time.Time) {
fmt.Println("Execution time: ", time.Now().Sub(startingTime))
}
23. A more complete example
func quicksort(arr []string, start, end int) {
if (end - start) < 1 {
return
}
pivot := arr[end]
splitIndex := start
for i := start; i < end; i++ {
if arr[i] < pivot {
arr[splitIndex], arr[i] = arr[i], arr[splitIndex]
splitIndex++
}
}
arr[end], arr[splitIndex] = arr[splitIndex], pivot
quicksort(arr, start, splitIndex-1)
quicksort(arr, splitIndex+1, end)
}
24. Output
$ go run main.go
Execution time: 1.000107637s
[uovedvemekymaops xrlzrshegtbdnows enhwynbzqfjpbmpq lhuxkoryozievjiu ecomkhxglzxdjngf kipvolyziwfagacv
knyjxajpcspjgkbc jthfcayshhotvcxj wipxnhtaoqlgtjsk oabiguaudkzryxfn]
At index 0, found ecomkhxglzxdjngf
At index 1, found enhwynbzqfjpbmpq
At index 2, found jthfcayshhotvcxj
At index 3, found kipvolyziwfagacv
At index 4, found knyjxajpcspjgkbc
At index 5, found lhuxkoryozievjiu
At index 6, found oabiguaudkzryxfn
At index 7, found uovedvemekymaops
At index 8, found wipxnhtaoqlgtjsk
At index 9, found xrlzrshegtbdnows
25. Go concurrency
func main() {
inputArray, _ := generateSlice(100)
wg := sync.WaitGroup{}
fmt.Println(inputArray)
quicksortConcurrent(wg, inputArray, 0, len(inputArray)-1)
wg.Wait()
fmt.Println("Finished")
for i, s := range inputArray {
fmt.Println(fmt.Sprintf("At index %d, found %s", i, s))
}
}
func quicksortConcurrent(wg sync.WaitGroup,arr
[]string,start,end int){
wg.Add(1)
defer wg.Done()
if (end - start) < 1 {
return
}
pivot := arr[end]
splitIndex := start
for i := start; i < end; i++ {
if arr[i] < pivot {
arr[splitIndex], arr[i] = arr[i], arr[splitIndex]
splitIndex++
}
}
arr[end], arr[splitIndex] = arr[splitIndex], pivot
go quicksortConcurrent(wg, arr, start, splitIndex-1)
go quicksortConcurrent(wg, arr, splitIndex+1, end)
}
26. Benchmark… Yet another Go feature...
package main
import (
"sync"
"testing"
)
var inputArray []string
func init() {
inputArray, _ = generateSlice(500)
}
func BenchmarkFuncNormal(b *testing.B) {
for i := 0; i < b.N; i++ {
quicksort(inputArray, 0, len(inputArray)-1)
}
}
func BenchmarkFuncConcurrent(b *testing.B) {
for i := 0; i < b.N; i++ {
quicksortConcurrent(sync.WaitGroup{}, inputArray, 0, len(inputArray)-1)
}
}
27. Let’s compare executions
$ go test -bench=.
goos: linux
goarch: amd64
pkg: geek
BenchmarkFuncNormal-4 862 1415186 ns/op
BenchmarkFuncConcurrent-4 10000 484759 ns/op
PASS
ok geek 7.233s
28. Go Channels
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
}
$ go run main.go
-5 17 12
29. Go dependency
go.mod
module geek
go 1.15
require (
cloud.google.com/go/firestore v1.3.0
github.com/lib/pq v1.8.0
)
$ go mod download
$ go get github.com/lib/pq
30. Is Go an object oriented language?
We can define structure and apply method on it
type Animal struct {
Name string // This is public
surname string // This is “private”
}
func (Animal) Speak() {
fmt.Println("I'm an animal")
}
func main() {
_ = Animal{
Name: "name",
surname: "Surname",
}
a := Animal{"name","surname"} //Work but not recommended
a.Speak()
}
31. Is Go an object oriented language?
There is also a way to embed types
type Dog struct {
Animal
}
func main() {
dog := Dog{
Animal{
Name: "Name",
Surname: "SurName",
},
}
dog.Name = "dog name"
dog.Speak() //Print I'm an animal
}
32. Is Go an object oriented language?
We can override method
func (d Dog) Speak() {
fmt.Println(fmt.Sprintf("I'm an dog and my name is %s", d.Name));
}
func main() {
dog := Dog{}
dog.Speak() //Print I'm a dog and my name is
}
33. Is Go an object oriented language?
But…
func main() {
dog := Dog{}
animals := []Animal{}
animals = append(animals, dog) //Cannot use 'dog' (type Dog) as type Animal
}
34. Is Go an object oriented language?
Solution
type Speaker interface {
Speak()
}
func main() {
dog := Dog{}
animals := []Speaker{}
animals = append(animals, dog)
for _, animal := range animals {
animal.Speak() //Print I'm an dog and my name is
}
}
35. Go has pointer
package main
import "fmt"
type Car struct {
Model string
}
func main() {
car := Car{Model: "Audi"}
ptrOnCar := &car
fmt.Println((*ptrOnCar).Model) // Print Audi
fmt.Println(ptrOnCar.Model) // Print Audi
}
36. Go pass by value
package main
import "fmt"
type Car struct {
Model string
}
func (c Car) SetModel(model string) {
c.Model = model
}
func main() {
car := Car{Model: "Audi"}
car.SetModel("BMW")
fmt.Println(car.Model) // Print Audi
}
package main
import "fmt"
type Car struct {
Model string
}
func (c *Car) SetModel(model string) {
c.Model = model
}
func main() {
car := Car{Model: "Audi"}
car.SetModel("BMW")
fmt.Println(car.Model) // Print BMW
}