Introduction
Parallelism vs concurrency
parallelism = do several summation at the same time.
concurrency = do several things at the same time. (things can be a mix of sum, substract, etc)
Three difficulties for concurrency
goroutine leaks
incomplete process
race condition
For 1 & 2 = 啟動一個goroutine一定要注意他是否能正常結束
For 3 = share memory by communication.
用channel 在不同goroutines間傳送數據, 就不用擔心race問題; channel is like event-driven (single thread) in JS.
goroutine vs thread
thread
sequence of instructions that managed independently by a scheduler
a web request creates a thread.
threads in a process share memory
a thread require >= 1MB
Switch threads needs to restore a lot of registers, and it calls to OS.
goroutine
in go virtual runtime, not OS.
>= 2kB
block goroutine = block specific threads. Others are not impact.
Do not communicate by sharing memory; instead, share memory by communicating.
communicate by sharing memory = 要有lock來避免race condition
share memory by communication = share memory 只在把channel從 goroutine A 傳到goroutine B.
Evaluation & execuation of goroutine
go f(x, y, z)
The evaluation of f, x, y, and z happens in the current goroutine.
The execution of f happens in the new goroutine.
Access to shared memory must be synchronized.
Goroutines run in the same address space.
Closing Channel
Only when the receiver must be told there are no more values coming, such as to terminate a range loop.
package main
import (
"fmt"
)
func main() {
c := make(chan int, 10)
go fibonacci(cap(c), c)
for i := range c {
fmt.Println(i)
} // c is in a receiver goroutine, and need a mechanism to tell it it empty.
}
func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
}
Select
A select
blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready.
package main
import (
"fmt"
"time"
)
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM!")
return
default:
fmt.Println(" .")
time.Sleep(50 * time.Millisecond)
}
}
}
.
.
tick.
.
.
tick.
.
.
tick.
.
.
tick.
.
.
BOOM!
Timeout
package main
import (
"fmt"
"log"
"net/http"
"time"
)
func main() {
response := make(chan *http.Response, 1)
errors := make(chan *error)
go func() {
resp, err := http.Get("http://matt.aimonetti.net/")
if err != nil {
errors <- &err
}
response <- resp
}()
for {
select {
case r := <-response:
fmt.Printf("%s", r.Body)
return
case err := <-errors:
log.Fatal(*err)
case <-time.After(200 * time.Millisecond):
fmt.Printf("Timed out!")
return
}
}
}
Last updated
Was this helpful?