GoLang is an open source programming language created by Google in 2009. It has a large community and was designed for scalability and concurrency. Some key features include being statically typed, compiled, and having built-in support for concurrency through goroutines and channels. Google uses GoLang extensively to build systems that scale to thousands of machines.
2. GoLang
Open Source
Huge community
Robert Griesemer, Rob Pike, Ken Thompson
Started at late 2009
1.0v published in March 2012
1.8v published in February 2017
•Go 1.8 (February 2017)
4. Scale at Google
System Scale
• Designed to scale to 106+ machines
• Everyday jobs run on 1000s machines
• Job coordinate, interacting with others in the system
• Lots going on at once
Solution: great support for concurrency
5. Scale at Google
Engineering Scale
• 500+ developers across 40+ offices
• 20+ changes per minute
• 50% of code base changes every month
• 50 million test cases executed per day
• Single code tree
Solution: design the language for large code bases
6. Pain Points
Slow Build Cross-language builds
Code hard to read Uncontrolled Dependencies
Each programmer using a different
subset of th language
Cost of updates
Version skew
Difficult of writing automatic tools
7. Why GoLang?
Simple (25 keywords)
Fast compiled, Modern
Compile into one executable file
Static Type-Checked, Fast Compiled
Garbage-Collected
Built-in Concurrency
•Go 1.8 (February 2017)
8. When to use Go?
System programming
Web apps
CLI based apps
Games
Scientific Apps
•Go 1.8 (February 2017)
11. Success Stories
Dailymotion: We like its simplicity, its performance and its static
type checking.
Dropbox: We decided to migrate our performance-critical backends
from Python to Go to leverage better concurrency support and faster
execution speed
Uber: We are extremely happy with our decision to Go for it and
write our service in a new language. Go typically takes just a few days
for a C++, Java or Node.js developer to learn, and the code is easy to
maintain
Tumblr: Go is an ideal language for writing web servers. It’s compiled
and integrates seamlessly with C libraries.
12. Success Stories
MongoDB: The Backup Service started as a Java project, but as the
project matured, the team wanted to move to a language that
compiled natively on the machine. After considering a few options,
the team decided that Go was the best fit.
Medium: Our Neo4j database is managed by a service written in Go.
Cloudfare: Go's concurrency makes writing software that must scale
up and down very easy.
14. Visual Studio Code with GoLang
https://golang.org/dl/
Delve debugger
go get github.com/derekparker/delve/cmd/dlv
Install Go extension for Visual Studio Code
17. Variables
• var i int var (
• var f float64 = 1.5 counter int64
• var b bool = true wg sync.WaitGroup
• var s string = "golang" )
Shortcut:
• i := 10
• s := "golang"
• f := 1.5
• b := false
No implicit numeric conversions
18. Array
Array bounds are always checked
var days [7]string
var board [4][2]int
var val [5]int = [5]int { 44, 72, 16, 1, 5 }
var counts = [...]int { 2,4,5,6 }
var scores = [5]int {1: 10, 2: 20}
19. Array
Passing an array between functions can be an expensive
operation in terms of memory and performance.
var array [8]int var array [8]int
foo(array) foo(&array)
func foo(array [8]int) { func foo(array *[8]int) {
... ...
} }
Passing pointer of array is only copy eight bytes.
20. Slice
Slices are built around the concept of dynamic arrays that can
grow and shrink
slice := make([]string, 5)
slice := []string{"Red", "Blue", "Green", "Yellow", "Pink"}
newSlice := slice[1:3]
newSlice = append(newSlice, 60)
21. Map
Maps don’t have a capacity or any restriction on growth
colors := map[string]string{}
colors["Red"] = "#da1337"
value, exists := colors["Blue"]
for key, value := range colors {
fmt.Printf("Key: %s Value: %sn", key, value)
}
func printColor(colors map[string]string) {
...
}
22. Function
func [<func-identifier>] ([<argument-list>]) [(<result-list>)] {
return [<value or expression list>]
}
func add(op0 int, op1 int) int {
return op0 + op1
}
func main() {
var opAdd func(int, int) = add
opAdd2 := add
}
23. Function
Variadic Functions:
func avg(nums ...float64) int
Return Parameters:
func div(op0, op1 int) (int, int) {
return q, r
}
func div(op0, op1 int) (q,r int) {
return
}
24. Function
Pass by reference:
func half(val *float64) {
*val = *val / 2
}
func main() {
num :=2.8
half(&num)
rad := func() float64 {
return 5 * math.Pi / 180
}()
}
25. Pointer
Similar to C/C++, Go uses the * operator to designate a type as
a pointer
var countPtr *int
var row []*int64
var a int = 1024
var aptr *int = &a
Unlike C, Go runtime maintains control of the management of
pointers at runtime. A programmer cannot add an arbitrary
integer value to the pointer to generate a new pointer address
26. OOP
struct Class with fields, only non-virtual methods
interface Class with only virtual methods
embedding Multiple inheritance and composition
27. Struct
No Constructor:
type user struct {
name string
email string
ext int
}
lisa := user {
name: "Lisa",
email: "lisa@email.com",
ext: 123
}
lisa := user{"Lisa", "lisa@email.com", 123}
28. Struct
No Inheritance / Composition:
type admin struct {
person user
level string
}
fred := admin {
person: user {
name: "Lisa",
email: "lisa@email.com",
ext: 123
},
level: "super"
}
29. Struct
No Inheritance / Embedding:
type Animal struct { type Dog struct {
legCount int Animal
} }
func (anm Animal) numberOfLegs int {
return anm.legCount
}
func main() {
d: = Dog(Animal(4))
fmt.Println("Leg count: %s", d.numberofLegs())
}
30. Interface
Implement all methods in interface:
type geometry interface { func main() {
area() float64 r: rect{ width:3, height:4 }
} measure(r)
type rect struct { }
width, height float64
}
func (r rect) area() float64 {
return r.width * r.height
}
func measure(g geometry) {
fmt.Println(g.area())
}
31. Packages
Name of the identifier itself carries the visibility
• Upper case : Public / exported / visible to other packages
• Lower case : Private to the package
import (
[identifier] "<path>"
)
import "fmt "
import vpr "github.com/spf13/viper"
import . "foo/bar/util/logger"
init(): function is invoked after the package-level variables are initialized
32. Error Handling
defer:
Pushing function to internal stack, delaying its execution
right before the enclosing function returns
• Closing open files
• Releasing network resources
• Closing channel
• Commiting database transactions
• Error handling
33. Error Handling
panic / recover:
func main() {
panicAndRecover()
fmt.Println("I need to run the statement at any cost!")
}
func panicAndRecover() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
panic("Unable to connect database!")
}
36. Concurrency
When a function is created as a goroutine, it’s treated as an
independent unit of work that gets scheduled and then
executed on an available logical processor
The Go runtime scheduler is a sophisticated piece of software
that manages all the goroutines that are created and need
processor time
The scheduler sits on top of the operating system, binding
operating system’s threads to logical processors which, in turn,
execute goroutines
40. Race Conditions
Go has a special tool that can detect race conditions in your
code.
go build –race //Build the code using the racind detector
./example //Run the code
------------------------------
WARNING: DATE RACE
Write by goroutine: 5
main.incCounter()
/example/main.go:49 +0x96
Previous read by goroutine 6:
main.main()
/example/main.go:49 +0x66
41. Locking
Go provides traditional support to synchronize goroutines by
locking access to shared resources
atomic.AddInt64(&counter, 1)
atomic.LoadInt64(&counter)
atomic.StoreInt64(&counter,1)
mutex.Lock() {
....
}
mutex.UnLock()
42. Channel
Don’t communicate by sharing memory, share memory by
communicating
Synchronize goroutines as they send and receive the resources
they need to share between each other
unbuffered := make(chan int)
buffered := make(chan string, 10)
value := <- buffered
buffered <- value
46. Garbage Collection
Tricolor Algorithm:
Initially color all nodes white (unexplored)
Color the root gray.
while some gray node x exist
color some white successors of x gray
if x has no successors left, color it black
Breadth-First
Mark and Sweep
Limit GC latency to less than 10 miliseconds
https://www.quora.com/Why-was-Docker-written-in-Go
https://github.com/docker
Like Docker, the Kubernetes project has been written in Go, Google's language for building distributed applications
Google's Kubernetes (Greek for "pilot," and the same word from which "cybernetic" is derived) is a management tool for deploying Docker containers into clusters of machines and for determining which nodes in the cluster would offer the best fit, based on their existing workloads.
Kubernetes is an open-source system for automating deployment, scaling and management of containerized applications that was originally designed by Google and donated to the Cloud Native Computing Foundation
Robert Grisemer: V8 Engine, Java Hotspot VM
Rob Pike: Develope Unix System, UTF-8
Ken Thompson: Creator of Unix System, UTF-8, Developed C lang
1.9v is expected to released in August, 2017. Now Rc2
Parallel Compilation
The Go compiler now supports compiling a package's functions in parallel, taking advantage of multiple cores.
This is in addition to the go command's existing support for parallel compilation of separate packages.
Parallel compilation is on by default, but can be disabled by setting the environment variable GO19CONCURRENTCOMPILATIONto 0.
Robert Grisemer: V8 Engine, Java Hotspot VM (left one)
Rob Pike: Develope Unix System, UTF-8 (Middle one)
Ken Thompson: Creator of Unix System, UTF-8, Developed C lang (right one)
Go team ( https://www.youtube.com/watch?v=sln-gJaURzk )
Go is answer to scale problem at Google. ( One executable file )
https://talks.golang.org/2012/splash.article
C, C++ written build server takes 45 minutes. ( include library ), With Go takes 5 minutes (Splash 2012 conf)
C open header file recursively so I/O so much
Modern => package management, Management thread
No need JVM, CLR (build to machine code, No need Go installed)
Advantages using with application container ( Docker )
https://play.golang.org/
Syntax ( Hello SGM )
Every time the function foo is called, eight megabytes of memory has to be allocated on the stack.
Then the value of the array, all eight megabytes of memory, has to be copied into that allocation.
Go can handle this copy operation, but there’s a better and more efficient way of doing this.
You can pass a pointer to the array and only copy eight bytes, instead of eight megabytes of memory on the stack
This time the function foo takes a pointer to an array of one million elements of type integer.
The function call now passes the address of the array, which only requires eight bytes of memory to be allocated on the stack for the pointer variable.
// Contains a length of 2 and capacity of 4 elements.
newSlice := slice[1:3] (20,30)
For slice[i:j] with an underlying array of capacity k
Length: j - i Capacity: k – I
For slice[1:3] with an underlying array of capacity 5
Length: 3 - 1 = 2
Capacity: 5 - 1 = 4
The append operation is clever when growing the capacity of the underlying array.
Capacity is always doubled when the existing capacity of the slice is under 1,000 elements.
Once the number of elements goes over 1,000, the capacity is grown by a factor of 1.25, or 25%.
This growth algorithm may change in the language over time.
Pass by reference
Invoking Anonymous Function :
func(f float64) float64 {
return (f - 32.0) * (5.0 / 9.0)
}(94)
This in itself isn't enough to replace inheritance, as embedding provides no form of polymorphism.
In other languages, inheritance hierarchies need to be carefully designed because changes are wide sweeping and therefore hard to do.
Go avoids these pitfalls while providing a powerful alternative.
Shadowing: defining another function or field with the same name
Type Base struct { X.A //int
A string X.Base.A //string
B float64 X.B //float64
}
Type Derived struct {
Base
A int
}
To implement an interface in Go, we just need to implement all the methods in the interface. Here we implement geometry on rects.
When an import statement uses the dot identifier (.) for an import path, it causes members of the imported package to be merged in scope with that of the importing package.
Therefore, imported members may be referenced without additional qualifiers
Sometimes a running goroutine may need to perform a blocking syscall, such as opening a file.
When this happens, the thread and goroutine are detached from the logical processor and the thread
continues to block waiting for the syscall to return. In the meantime, there’s a logical processor without a thread.
So the scheduler creates a new thread and attaches it to the logical processor. Then the scheduler
will choose another goroutine from the local run queue for execution. Once the syscall returns,
the goroutine is placed back into a local run queue, and the thread is put aside for future use.
If a goroutine needs to make a network I/O call, the process is a bit different. In this case, the goroutine
is detached from the logical processor and moved to the runtime integrated network poller.
Once the poller indicates a read or write operation is ready, the goroutine is assigned back to a logical processor to handle the operation
There’s no restriction built into the scheduler for the number of logical processors that can be created.
But the runtime limits each program to a maximum of 10,000 threads by default. This value can be changed
by calling the SetMaxThreads function from the runtime/debug package. If any program attempts to use more threads, the program crashes.
Concurrency is not parallelism. Parallelism can only be achieved when multiple pieces of code are executing simultaneously against different physical processors.
Parallelism is about doing a lot of things at once. Concurrency is about managing a lot of things at once. In many cases, concurrency can outperform parallelism,
because the strain on the operating system and hardware is much less, which allows the system to do more
If you want to run goroutines in parallel, you must use more than one logical processor. When there are multiple logical processors, the scheduler will evenly
distribute goroutines between the logical processors. This will result in goroutines running on different threads
It’s not recommended to blindly change the runtime default for a logical processor. The scheduler contains intelligent algorithms that are updated and improved with every release of Go
The function contains a call to the Gosched function from the runtime package on line 43 to yield the thread and give the other goroutine a chance to run
runtime.Gosched();
Counter => a int64 variable
An unbuffered channel is a channel with no capacity to hold any value before it’s received.
These types of channels require both a sending and receiving goroutine to be ready at the same instant
before any send or receive operation can complete. If the two goroutines aren’t ready at the same instant,
the channel makes the goroutine that performs its respective send or receive operation first wait
In step 1 the two goroutines approach the channel, but neither have issued a send or receive yet.
In step 2 the goroutine on the left sticks its hand into the channel, which simulates a send on the channel.
At this point, that goroutine is locked in the channel until the exchange is complete.
In step 3 the goroutine on the right places its hand into the channel, which simulates a receive on the channel. That goroutine is now locked in the channel until the exchange is complete.
In steps 4 and 5 the exchange is made and finally,
in step 6, both goroutines are free to remove their hands, which simulates the release of the locks.
A buffered channel is a channel with capacity to hold one or more values before they’re received. These types of channels don’t force goroutines to be ready at the same instant to perform sends and receives. There are also different conditions for when a send or receive does block. A receive will block only if there’s no value in the channel to receive. A send will block only if there’s no available buffer to place the value being sent. This leads to the one big difference between unbuffered and buffered channels: An unbuffered channel provides a guarantee that an exchange between two goroutines is performed at the instant the send and receive take place. A buffered channel has no such guarantee.
In step 1 the goroutine on the right is in the process of receiving a value from the channel. In step 2 that same goroutine is able to complete the receive independent of the goroutine on the left sending a new value into the channel. In step 3 the goroutine on the left is sending a new value into the channel while the goroutine on the right is receiving a different value. Neither of these two operations in step 3 are in sync with each other or blocking. Finally, in step 4 all the sends and receives are complete and we have a channel with several values and room for more.
Two types of garbage collector:
Reference Counting: Each object has a count of other objects referencing it
Sensitive to cycle referencing
Not real-time
Must be atomic
Increasing space overhead
Tracing garbage collector: Determine which objects are reachable from a certain «root» object
Unreachable objects are considerable as garbage