concurrency

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

  1. goroutine leaks

  2. incomplete process

  3. 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

  1. sequence of instructions that managed independently by a scheduler

  2. a web request creates a thread.

  3. threads in a process share memory

  4. a thread require >= 1MB

  5. Switch threads needs to restore a lot of registers, and it calls to OS.

goroutine

  1. in go virtual runtime, not OS.

  2. >= 2kB

  3. 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?