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: