golang concurrent basis

1. go协程(go routine)

go native support for concurrency: goroutine and channel.

go coroutine functions and methods is to run concurrently with other functions or methods. go coroutines can be viewed as a lightweight thread.

When you call a function or method, preceded by the keyword go, you can make a new GO coroutine to run concurrently.

  • When l start a new coroutine, coroutine call will return immediately. With different functions, program control not going to wait for Go coroutine is finished. Go after calling coroutine, program control returns immediately to the next line of code, ignoring any return value of the coroutine.
  • l If you want to run other coroutine Go, Go main coroutine must continue running. If the main Go coroutine terminated, the program is terminated, then the other Go coroutine will not continue to run.

2. Nobumichi channel

Into a pipe communication channel between Go conceivable coroutine.

Chan T represents a T type channels. Associated with the type of channel, only the type of data transport.

Channel zero is nil. Zero value of the channel is no use, it should be like on the map and sliced done, make use to define the channel.

Data: = <- a // read channel a   
a <- Data // write channel a

The default channel transmission and reception is blocked.

Channel will deadlock. Go coroutine when transmitting data to a channel, and no data channel reception, panic procedures violated, formed deadlock.

Unidirectional channel

sendch: = the make (Chan <- int )     // define unidirectional channel

It can be converted into a bidirectional channel CD or CD transport channel reception channel (send only or receive only), but not vice versa.

Close Channel

The data sender can close the channel, inform the receiver that no channel data is sent.

When data is received from a channel, the recipient can use a multi-variable to check whether a channel has been closed.

in, ok = <- CH

If the channel can receive the data, ok equal to true; if the channel is closed, ok equal to false.

Zero value when the channel type of the value read from a closed to channel.

ergodic channel range

for range before the loop for a closed channel, receives data from the channel.

    ch := make(chan int)
    go producer(ch)
    for v := range ch {
        fmt.Println("Received ",v)
    }

3. The buffered channel

buffered Channel case only buffer is full before transmitting data blocking, the same buffer only when an empty blocking receive data.

ch := make(chan type, capacity)   // capacity大于0

Capacity of the buffer channel refers to the number of channels can be stored value. The length of the buffer channel is the number of elements currently queued channel.

4. Work Pool

WaitGroup Go wait for a number of coroutine execution ends. Program control will remain blocked until all these coroutine is finished.

Definitions: var wg sync.WaitGroup

Call: wg.Add (1) ... wg.Done () ... wg.Wait ()

package main

import (  
    "fmt"
    "sync"
    "time"
)

func process(i int, wg *sync.WaitGroup) {  
    fmt.Println("started Goroutine ", i)
    time.Sleep(2 * time.Second)
    fmt.Printf("Goroutine %d ended\n", i)
    wg.Done()
}

func main() {  
    no := 3
    var wg sync.WaitGroup
    for i := 0; i < no; i++ {
        wg.Add(1)
        go process(i, &wg)
    }
    wg.Wait()
    fmt.Println("All go routines finished executing")
}

output:
started Goroutine  2
started Goroutine  0
started Goroutine  1
Goroutine 1 ended
Goroutine 2 ended
Goroutine 0 ended
All go routines finished executing

Coroutine mass participation wg address is very important, wg.Done () finished emperor coroutine know. If the value of copies, main function does not know.

package main

import (
        "fmt"
        "math/rand"
        "sync"
        "time"
)

type Job struct {
        id int
        randomno int
}

type Result struct{
        job Job
        sumofdigits int
}

var jobs = make(chan Job, 10)
var results = make(chan Result, 10)

func sum_digits(number int)int {
        sum := 0
        for number !=0 {
                i:= number%10
                sum += i
                number = number/10
        }
        time.Sleep(2*time.Second)
        return sum
}
func worker(wg *sync.WaitGroup){
        for job := range jobs{
                output := Result{job, sum_digits(job.randomno)}
                results <- output
        }

        wg.Done()
}

func create_worker_pool(num_workers int){
        var wg sync.WaitGroup
        for i:=0; i < num_workers; i++{
                wg.Add(1)
                go worker(&wg)
        }
        wg.Wait()
        close(results)
}

func allocate(num_jobs int){
        for i := 0; i < num_jobs; i++{
                randomno := rand.Intn(999)
                job := Job{i, randomno}
                jobs <- job
        }
        close(jobs)
}
func result(done chan bool){
        for result := range results{
                fmt.Printf("Job id %d, input random no %d, sum of digits %d\n", result.job.id, result.job.randomno, result.sumofdigits)
        }
        done <- true
}

func main(){
        startTime := time.Now()
        num_jobs := 100
        go allocate(num_jobs)
        done := make(chan bool)
        go result(done)
        num_workers := 10
        create_worker_pool(num_workers)
        <-done
        endTime := time.Now()
        diff := endTime.Sub(startTime)
        fmt.Println("total time taken ", diff.Seconds(), "seconds")
}

5.select

select Statement for transmitting / receiving channel select a plurality of operation. select Statement blocks until the send / receive operation is ready. If there are multiple channel operation is ready, select it will perform one of the randomly selected. The syntax is  switch similar, except that, where each  case statement is channel operation.

In the absence of case ready to be executed  select by default statement (Default Case). This is usually used to prevent  select statement has been blocked.

package main

import (  
    "fmt"
    "time"
)

func server1(ch chan string) {  
    time.Sleep(6 * time.Second)
    ch <- "from server1"
}
func server2(ch chan string) {  
    time.Sleep(3 * time.Second)
    ch <- "from server2"

}
func main() {  
    output1 := make(chan string)
    output2 := make(chan string)
    go server1(output1)
    go server2(output2)
    select {
    case s1 := <-output1:
        fmt.Println(s1)
    case s2 := <-output2:
        fmt.Println(s2)
    }
}

select Application: Suppose we have a critical application, we need to export as soon as possible to the user. The application of database replication and stored on servers around the world. We send requests to both servers, and use the  select statement waits for a response from the corresponding channel. select We will choose the server responds first, and ignore the other responses. Using this method, we can send requests to multiple servers, and the user returns to the fastest response.

package main

func main() {  
    select {}
}

select Statement does not have any case, it would have been blocked, leading to a deadlock. The program will trigger panic.

6.mutex

Mutex used to provide a locking mechanism (Locking Mechanism), ensures that only a coroutine run a critical section at a time, to prevent a race condition occurs.

var mutex sync.Mutex
mutex.Lock()  
x = x + 1  
mutex.Unlock()

Channel processing race conditions

    ch <- true
    x = x + 1
    <- ch

When Go coroutine need to communicate with other co-routines, you may use the channel. When only a coroutine access the critical section, may be used Mutex.

 

reference:

1.   https://studygolang.com/subject/2

Guess you like

Origin www.cnblogs.com/embedded-linux/p/11128844.html