Sriharsha Sistalam
Project manager at D.E.Shaw India. Interested in front end, distributed systems, micro services.
Sriharsha Sistalam
Go is yet another open compiled, staticly typed open source programming language created at Google by Robert Griesemer, Rob Pike and Ken Thompson
C/C++ languages gets compiled to assembly, then to executable machine code.
Java first to bytecode, then to machine code (JVM)
Perl/Python, each line is interpreted one by one and gets executed.
Go programs are directly compiled to machine code (binaries)
//helloworld file
$cat helloworld.go
package main
import "fmt"
func main(){
fmt.Println("Hello world")
//build the code
$go build helloworld.go
$ls hellworld*
helloworld helloworld.go
//execute it
$./helloworld
Hello World
Go was created at Google to address various issue they were facing due to their sheer size and scale.
Google wanted something that can be fastly compiled, with less type heirarchical, fully garbage collected, mainly concurrent executable. So they went ahead and built Go
"Go is an attempt to combine the ease of programming of an interpreted, dynamically typed language with the efficiency and safety of a statically typed, compiled language"
# package name
package main
# import all the standard/third party libraries here
# even from github directly
import "fmt"
# main execution
func main(){
#use a function under fmt package to print to screen
fmt.Println("Hello world")
}
➜ ~ cat add.go
package main
import "fmt"
func main(){
var a,b int = 5, 6 # explicit variable declaration
fmt.Println(a + b)
}
➜ ~ go build add.go
➜ ~ ./add
11
Built in concurrency
Standard library modules
functions as first class citizens
All other features of normal language like functions, data types, packages, package management, compiling/build/test tools, version control.
Concurrency is built into the language and it is a first class citizen just like functions.
It is a function that is capable of running concurrently with other functions (within same process)
Goroutines are lightweight and we can easily create thousands of them, they are simillar to light weight processes of erlang
Threads | Goroutines | |
Runtime | Runs as OS threads | They are multiplexed on OS threads |
Memory | Significant memory is used for each thread (~ 1MB) | Less memory (~2KB) is used for each Goroutine |
Setup/Tear down cost | High since OS is involved | They are created and managed by runtime, hence overhead is less |
Switching costs | Context switch will result in saving of various register data, pretty significant if switching happens often | |
GP registers, Stack prointer, Program counter, Segments registers | Program counter, Stack pointer, DX |
In Go, routines are created by calling a function prefixed by 'go'
// A _goroutine_ is a lightweight thread of execution.
package main
import "fmt"
func f(from string) {
for i := 0; i < 3; i++ {
fmt.Println(from, ":", i)
}
}
func main() {
// synchronously.
f("direct")
// concurrently
go f("goroutine")
// You can also start a goroutine for an anonymous
// function call.
go func(msg string) {
fmt.Println(msg)
}("going")
// Our two function calls are running asynchronously in
// separate goroutines now, so execution falls through
// to here. This `Scanln` code requires we press a key
// before the program exits.
var input string
fmt.Scanln(&input)
fmt.Println("done")
}
Channels are used as communication medium between two or more goroutines, they provide a way for synchronizing the execution of different parts of system.
They are analogous to unix pipes which provides the glue between multiple programs
package main
import "fmt"
import "time"
// This is the function we'll run in a goroutine. The
// `done` channel will be used to notify another
// goroutine that this function's work is done.
func worker(done chan string) {
fmt.Print("working...")
time.Sleep(time.Second)
fmt.Println("done")
// Send a value to notify that we're done.
done <- "Function is done"
}
func main() {
// Start a worker goroutine, giving it the channel to
// notify on.
done := make(chan string, 1)
go worker(done)
// Block until we receive a notification from the
// worker on the channel.
fmt.Println(<-done)
}
Various types of channels like inbound, outbound, multi plexed etc exist. Values of any type can be communicated through this channel.
Communicating sequential processes is the standard design on which many concurrent languages are designed
"Do not communicate by sharing, share by communicating"
Usual way of multi threading by shared memory
CSP suggested way of handling without shared memory (wrt golang)
Have two threads/components/routines/functions which produces a sequence of numbers and a main function which consumes these numbers concurrently
//this produces even numbers
func printEvenNumbers(ch chan int){
for i:=2; i<=45; i=i+2 {
ch<-i;
}
close(ch);
}
//this produces odd numbers
func printOddNumbers(ch chan int){
for i:=1; i<=25; i=i+2 {
ch<-i;
}
close(ch);
}
//main function which consumes all numbers
func main() {
var a = make(chan int);
var b = make(chan int);
go printOddNumbers(a);
go printEvenNumbers(b);
var c = merge_alternate(a, b)
for i:= range c {
fmt.Println(i);
}
}
//main function
Thread t1 = new Thread(new Counter(numbers, false));
Thread t2 = new Thread(new Counter(numbers, true));
try {
t1.start(), t2.start();
t1.join(), t2.join();
System.out.println(numbers);
} catch (Exception e) {
System.exit(1);
}
class Counter extends Thread {
static List<Integer> numbers; boolean even;
//constructor
public void run(){
int itr = this.even ? 2: 1;
System.out.println("Starting " + itr);
for (; itr < 53; itr = itr + 2) {
synchronized (numbers) {
numbers.add(itr);
try {
numbers.notify();
numbers.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("Done in run");
}
}
Select: It lets you wait on selected channel operations.
// _Timeouts_ are important for programs that connect to
// external resources or that otherwise need to bound
// execution time. Implementing timeouts in Go is easy and
// elegant thanks to channels and `select`.
package main
import "time"
import "fmt"
func main() {
// For our example, suppose we're executing an external
// call that returns its result on a channel `c1`
// after 2s.
c1 := make(chan string, 1)
go func() {
time.Sleep(time.Second * 2)
c1 <- "result 1"
}()
// Here's the `select` implementing a timeout.
// `res := <-c1` awaits the result and `<-Time.After`
// awaits a value to be sent after the timeout of
// 1s. Since `select` proceeds with the first
// receive that's ready, we'll take the timeout case
// if the operation takes more than the allowed 1s.
select {
case res := <-c1:
fmt.Println(res)
case <-time.After(time.Second * 1):
fmt.Println("timeout 1")
}
}
Implementing a thread pool of process tasks
package main
import "fmt"
import "time"
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Println("worker", id, "processing job", j)
time.Sleep(time.Second)
results <- j * 2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
for j := 1; j <= 9; j++ {
jobs <- j
}
close(jobs)
for a := 1; a <= 9; a++ {
<-results
}
Dining philosophers
type Philosopher struct {
name string
chopstick chan bool
neighbor *Philosopher
}
func (phil *Philosopher) getChopsticks() {
timeout := make(chan bool, 1)
go func() { time.Sleep(1e9); timeout <- true }()
<-phil.chopstick
fmt.Printf("%v got his chopstick.\n", phil.name)
select {
case <-phil.neighbor.chopstick:
fmt.Printf("%v got %v's chopstick.\n", phil.name, phil.neighbor.name)
fmt.Printf("%v has two chopsticks.\n", phil.name)
return
case <-timeout:
phil.chopstick <- true
phil.think()
phil.getChopsticks()
}
}
Go is really good at handling things for "scale" which requires both high throughput as well as high concurrency.
Text
TCP programming, sockets (Websockets)
Programs that involves distribution of work across workers (nginx)
Yes, users are mainly shifting out of Nodejs to Go for below reasons
References:
Thank you
By Sriharsha Sistalam
Project manager at D.E.Shaw India. Interested in front end, distributed systems, micro services.