Golang Concurrency Model

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

There are three classic ways to control concurrency, one is to implement concurrency control through channel notifications, and the other is the context, Waitgroup.

1. Implementing concurrency control using the most basic channel notification

No buffer channel

Unbuffered channels refer to the size of the channel 0, meaning that this type of channel does not have the ability to hold any value before it is received, and it requires goroutine both sending and receiving to goroutine be ready to complete the send and receive operations.

From the non-buffered channel definition above, the send goroutine and receive gouroutine must be synchronous, and when prepared, the first action will block the wait until another corresponding operation is ready. This unbuffered channel is also known as a synchronous channel.

Formally implement multi-concurrency control via unbuffered channels goroutine

func main() {    ch := make(chan instruct{})    go func() {        ch <- struct{}{}    }()    fmt.Println(<-ch)}

When the master goroutine runs to the <-ch accepted channel value, if channel there is no data in it, the wait is blocked until there is a value. This makes it easy to implement concurrency control

2. Implementing concurrency control via the Waitgroup in the Sync pack

In the sync package, provided WaitGroup , it waits for all the tasks it collects to goroutine complete, goroutine Add(delta int) asking for the number of Waits goroutine in the master. After each completion, goroutine it is Done() indicated that this one goroutine has been completed, and when all is done, returns are returned goroutine in the master goroutine WaitGroup .

fun main(){    var wg sync.WaitGroup    var urls = []string{        "http://www.golang.org/",        "http://www.google.com/",        "http://www.somestupidname.com/",    }    for _, url := range urls {        wg.Add(1)        go func(url string) {            defer wg.Done()            http.Get(url)        }(url)    }    wg.Wait()}

But in the Golang official website, there is such a sentence

    • A Waitgroup must not being copied after first use.

The translation is enough to come, WaitGroup after the first use, cannot be copied, because there will be a problem

func main() {    wg := sync.WaitGroup{}    for i := 0; i < 5; i++ {        wg.Add(1)        go func(wg sync.WaitGroup, i int) {            log.Printf("i:%d", i)            wg.Done()        }(wg, i)    }    wg.Wait()    log.Println("exit")}

The operation results are as follows

2009/11/10 23:00:00 i:42009/11/10 23:00:00 i:02009/11/10 23:00:00 i:12009/11/10 23:00:00 i:22009/11/10 23:00:00 i:3fatal error: all goroutines are asleep - deadlock!goroutine 1 [semacquire]:sync.runtime_Semacquire(0x1040a13c, 0x44bc)    /usr/local/go/src/runtime/sema.go:47 +0x40sync.(*WaitGroup).Wait(0x1040a130, 0x121460)    /usr/local/go/src/sync/waitgroup.go:131 +0x80main.main()    /tmp/sandbox894380819/main.go:19 +0x120

It prompts me that all of goroutine them have slept, and there is a deadlock. This is because the wg copy is passed to the goroutine middle, resulting in only the Add operation, in fact the Done operation is wg executed in the copy. So Wait it's dead locked.

Four types of references in Go are slice, channel, function, map

    • Correction Method One:
      Change the incoming type in the anonymous function wg *sync.WaitGrou so that you can refer to the correct waitgroup.

    • Correction Method Two:
      Remove the incoming parameters from the anonymous function wg because go supports the closure type, and the outside variables can be used directly in the anonymous function wg

3. Powerful context context introduced after go 1.7 for concurrency control

3.1 Introduction

It is enough to use in some simple scenarios channel WaitGroup , but when faced with some complex and changeable network concurrency scenarios channel and WaitGroup seems a little overwhelmed. For example, a network request Request , each Request need to open one to goroutine do something, which goroutine may open other goroutine , such as the database and RPC services. So we need a way to keep track of what we can do to goroutine control them, and that's what the go language provides for us Context , called context, which is goroutine the context. It is a program that includes a running environment, a scene, and snapshots. Every time a program is run, it needs to know the current program's running state, usually go wraps it in one Context , and then passes it to the execution goroutine . contextpackages are primarily used to deal with multiple goroutine shared data, and multiple goroutine management.

3.2 Package Context

contextThe core of the package is struct Context that the interface is declared as follows:

 //a Context carries a deadline, cancelation signal, and request-scoped values//across API Boundari Es. Its methods is safe for simultaneous use by multiple//Goroutines.type Context Interface {//Done returns a channel T    Hat is closed if this ' Context ' is canceled//or times out.    Done () <-chan struct{}//ERR indicates why this Context was canceled, after the Do channel//is closed.    ERR () error//Deadline returns the time when this Context would be is canceled, if any. Deadline () (Deadline time.    Time, OK bool)//value returns the value associated with key or nil if none. Value (Key interface{}) interface{}}  
    • Done()Returns a type that accepts only data channel , and when the context is closed or the time- out expires , the channel has a cancellation signal
    • Err()Done()after that, the context reason for the cancellation is returned.
    • Deadline()Set the context cancel point in time
    • Value()Method allows an Context object to carry scoped request data, which must be thread-safe.

ContextThe object is thread-safe, and you can Context pass an object to any number gorotuine , and all goroutine will receive a cancellation signal when it cancels the operation.

One Context cannot have a Cancel method, and we can only Done channel receive data.
The reason behind this is consistent: the function that receives the cancellation signal and the function that sends the signal is usually not one.
A typical scenario is that the parent action starts as a child action operation goroutine and the child action cannot cancel the parent operation.

3.3 Inheriting the context

The context package provides functions to assist users in Context creating new objects from existing objects Context .
These Context objects form a tree: When an Context object is canceled, all inherited from it Context will be canceled.

Backgroundis Context the root of all object trees and it cannot be canceled. It declares the following:

// Background returns an empty Context. It is never canceled, has no deadline,// and has no values. Background is typically used in main, init, and tests,// and as the top-level `Context` for incoming requests.func Background() Context

WithCanceland WithTimeout functions return inherited Context objects that can be canceled earlier than their parent Context .

When the request handler function returns, the request is associated with a Context cancellation. When you use multiple replicas to send a request, you can use WithCancel the Cancel extra request. WithTimeoutuseful when setting a time-out for back-end server requests. Here are the declarations of these three functions:

// WithCancel returns a copy of parent whose Done channel is closed as soon as// parent.Done is closed or cancel is called.func WithCancel(parent Context) (ctx Context, cancel CancelFunc)// A CancelFunc cancels a Context.type CancelFunc func()// WithTimeout returns a copy of parent whose Done channel is closed as soon as// parent.Done is closed, cancel is called, or timeout elapses. The new// Context's Deadline is the sooner of now+timeout and the parent's deadline, if// any. If the timer is still running, the cancel function releases its// resources.func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)

WithValueThe function can relate the data of the request scope to the Context object. The statement reads as follows:

// WithValue returns a copy of parent whose Value method returns val for key.func WithValue(parent Context, key interface{}, val interface{}) Context

3.4 Context Example

Of course, to know how the Context package works, the best way is to look at an example.

 func childfunc (cont context. Context, num *int) {CTX, _: = Context. Withcancel (cont) for {select {case <-ctx. Done (): FMT. PRINTLN ("Child-Done:", ctx.) ERR ())) return}}}func main () {gen: = Func (CTX context. Context) <-chan int {dst: = make (chan int) N: = 1 Go func () {for {sel ECT {case <-ctx. Done (): FMT. Println ("Parent Done:", ctx.)                    ERR ()) return//Returning leak the Goroutine case DST <-N:  n++ Go Childfunc (CTX, &n)}} () return DST} CTX, Cancel: = context. Withcancel (context. Background ()) for n: = Range Gen (ctx) {fmt. PRINTLN (n) if n >= 5 {Break}} cancel () time. Sleep (5 * time. Second)}  

In the example above, the main description is to channel implement a loop with a loop number of 5,
In each loop, one is generated, goroutine each goroutine is passed in context , goroutine a child ctx Context is created by passing in each, and the select running condition is monitored by the Context parent Context When exiting, the code does not clearly call the sub Context - Cancel function, but the analysis results, the child Context is properly closed, this is because, all based on this Context or derivative of the child Context will be notified, then can be cleaned up the operation, Eventually released goroutine , this elegantly solves the goroutine problem of uncontrolled startup.

Here is the result of the operation:


Picture. png

3.5 Context Usage Principles

    • do not place the context in the struct, and you want to pass the
    • context function method as a parameter by passing the context As the first parameter, place the first bit.
    • When passing context to a function method, do not pass nil and use Context if you do not know what to pass. TODO
    • context Value related methods should pass the necessary data, and do not use any data for this pass
    • Context is thread-safe and can be safely passed in multiple goroutine

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.