Go concurrent language _

Concurrent
Go concurrent structure as part of the core language. This section describes some examples of courses and demonstrated their use.

Go write authors group, Go-zh group translation.
https://tour.go-zh.org/concurrency/1

  • Go as

Go Cheng (goroutine) is managed by the Go run when lightweight threads.

go f(x, y, z)

We will start a new process and executes Go

f(x, y, z)

f, x, yAnd zevaluated occur in the current process of Go, and fthe execution take place in the new Go process.

Go away run in the same address space, it must be synchronized when accessing shared memory. [[ Https://go-zh.org/pkg/sync/ ] [ sync]] package provides this capability, but it is not often used in Go, because there are other ways (see next page).

// +build OMIT

package main

import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go say("world")
    say("hello")
}
  • Nobumichi

Channel is a pipe with a type, you can use the channel through which the operator <-is transmitted or received values.

ch <- v    // 将 v 发送至信道 ch。
v := <-ch  // 从 ch 接收值并赋予 v。

( "Arrow" is the direction of data flow.)

And maps and sections, like the channel must be created before using:

ch := make(chan int)

By default, send and receive operations are blocked until the other end is ready. This process can be synchronized such that Go without explicit lock variable or race conditions.

The following example summing the number of sections, assign tasks to process two Go. Once the process is complete their Go two calculations, it can be calculated from the final result.

// +build OMIT

package main

import "fmt"

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum // 将和送入 c
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)
    x, y := <-c, <-c // 从 c 中接收

    fmt.Println(x, y, x+y)
}
  • Channel Buffered

Channel may be buffered . The length of the buffer as the second parameter provided to the makechannel buffer is initialized with:

ch := make(chan int, 100)

Only when the channel buffer is full, data will be transmitted thereto obstruction. When the buffer is empty, the recipient will be blocked.

Modify the sample to fill the buffer, and then see what happens.

// +build OMIT

package main

import "fmt"

func main() {
    ch := make(chan int, 2)
    ch <- 1
    ch <- 2
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}
  • range 和 close

The sender can closebe transmitted to a value indicating no need to turn off one channel. The recipient can be tested whether a channel is closed by an expression assigned to receive a second argument: if there is no value can be received and the channel has been closed, then executing the

v, ok := <-ch

At this point okit will be set false.

Cyclic forI :=Range cconstantly receives values from the channel, until it is closed.

Note: Only the sender can close the channel, and the receiver can not. Transmitting data to a channel that has been closed the program will cause panic (panic).

Also note: different channels and files, usually without having to close them. Only when it is necessary to tell the recipient no longer has value only needs to transmit necessary to close, such as termination of a rangecycle.

// +build OMIT

package main

import (
    "fmt"
)

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)
}

func main() {
    c := make(chan int, 10)
    go fibonacci(cap(c), c)
    for i := range c {
        fmt.Println(i)
    }
}
  • select statement

select Go to make a statement process can wait a plurality of communication operations.

selectClog to a branch can continue to perform, at which time it will execute the branch. When multiple branches are ready randomly selects an execution.

// +build OMIT

package main

import "fmt"

func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:
            x, y = y, x+y
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}

func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            fmt.Println(<-c)
        }
        quit <- 0
    }()
    fibonacci(c, quit)
}
  • The default selection

When selectthe time in other branches are not ready, defaultthe branch will be executed.

In order not to clog occurs while trying to send or receive, using defaultbranches:

select {
case i := <-c:
    // 使用 i
default:
    // 从 c 中接收会阻塞时执行
}
// +build OMIT

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)
        }
    }
}
  • Exercise: equivalent binary search tree

The same sequence of values can be stored on a different leaf node of a binary tree. For example, the following sequence of two binary trees are saved 1,1,2,3,5,8,13.

.image /content/img/tree.png

In most languages, to check whether two binary trees to save the same sequence of functions are quite complicated.
We will use Go's concurrency and channel to write a simple solution.

This embodiment uses a treepackage, which defines the type:

type Tree struct {
    Left  *Tree
    Value int
    Right *Tree
}

Click [[ JavaScript: the Click ( '.next-Page')] [next page]] to continue.

  • Exercise: equivalent binary search tree

1. implement Walkfunctions.

2. Test Walkfunction.

Function is tree.New(k)used to construct a random structure sorted binary search tree, it holds the value of k, 2k, 3k, ..., 10k.

Create a new channel chand its stepper:

go Walk(tree.New(1), ch)

10 and then reads the values from the print channel. It should be a number 1,2, 3,..., 10.

3. used Walkto achieve Samethe function to detect t1and t2whether to store the same values.

4. The test Samefunction.

Same(tree.New(1),tree.New (. 1)) 应当返回to true ,而Same, (tree.New (. 1), tree.New(2))should be returned false.

TreeThe documents are available on [[ https://godoc.org/golang.org/x/tour/tree#Tree ] [here]] found.

// +build no-build OMIT

package main

import "golang.org/x/tour/tree"

// Walk 步进 tree t 将所有的值从 tree 发送到 channel ch。
func Walk(t *tree.Tree, ch chan int)

// Same 检测树 t1 和 t2 是否含有相同的值。
func Same(t1, t2 *tree.Tree) bool

func main() {
}
  • sync.Mutex

We have seen very suitable channel for communication between the various Go away.

But if we do not need to communicate it? For example, if we just want to ensure that only one process can access the Go a shared variable, so as to avoid conflict?

The concept involved here is called a mutex (Mutual Exclusion) *, we usually use mutex (Mutex) the data structures to provide such a mechanism.

Providing Go [[standard library https://go-zh.org/pkg/sync/#Mutex ] [ sync.Mutex]] and the mutex type two methods:

  • Lock
  • Unlock

We can call the code before the Lockmethod, after the code calls the Unlockmethod to ensure the implementation of a code of mutual exclusion. See Incmethods.

We can also use the deferstatement to ensure mutex will be unlocked. See Valuemethods.

// +build OMIT

package main

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

// SafeCounter 的并发使用是安全的。
type SafeCounter struct {
    v   map[string]int
    mux sync.Mutex
}

// Inc 增加给定 key 的计数器的值。
func (c *SafeCounter) Inc(key string) {
    c.mux.Lock()
    // Lock 之后同一时刻只有一个 goroutine 能访问 c.v
    c.v[key]++
    c.mux.Unlock()
}

// Value 返回给定 key 的计数器的当前值。
func (c *SafeCounter) Value(key string) int {
    c.mux.Lock()
    // Lock 之后同一时刻只有一个 goroutine 能访问 c.v
    defer c.mux.Unlock()
    return c.v[key]
}

func main() {
    c := SafeCounter{v: make(map[string]int)}
    for i := 0; i < 1000; i++ {
        go c.Inc("somekey")
    }

    time.Sleep(time.Second)
    fmt.Println(c.Value("somekey"))
}
  • Exercise: Web Crawler

In this exercise, we will use Go's concurrency features to parallelize a Web crawler.

Modify Crawlfunction parallel grab URL, and guaranteed not repeated.

Tip : You can use a map to cache already acquired URL, but be careful map itself is not complicated by security!

// +build OMIT

package main

import (
    "fmt"
)

type Fetcher interface {
    // Fetch 返回 URL 的 body 内容,并且将在这个页面上找到的 URL 放到一个 slice 中。
    Fetch(url string) (body string, urls []string, err error)
}

// Crawl 使用 fetcher 从某个 URL 开始递归的爬取页面,直到达到最大深度。
func Crawl(url string, depth int, fetcher Fetcher) {
    // TODO: 并行的抓取 URL。
    // TODO: 不重复抓取页面。
        // 下面并没有实现上面两种情况:
    if depth <= 0 {
        return
    }
    body, urls, err := fetcher.Fetch(url)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("found: %s %q\n", url, body)
    for _, u := range urls {
        Crawl(u, depth-1, fetcher)
    }
    return
}

func main() {
    Crawl("https://golang.org/", 4, fetcher)
}

// fakeFetcher 是返回若干结果的 Fetcher。
type fakeFetcher map[string]*fakeResult

type fakeResult struct {
    body string
    urls []string
}

func (f fakeFetcher) Fetch(url string) (string, []string, error) {
    if res, ok := f[url]; ok {
        return res.body, res.urls, nil
    }
    return "", nil, fmt.Errorf("not found: %s", url)
}

// fetcher 是填充后的 fakeFetcher。
var fetcher = fakeFetcher{
    "https://golang.org/": &fakeResult{
        "The Go Programming Language",
        []string{
            "https://golang.org/pkg/",
            "https://golang.org/cmd/",
        },
    },
    "https://golang.org/pkg/": &fakeResult{
        "Packages",
        []string{
            "https://golang.org/",
            "https://golang.org/cmd/",
            "https://golang.org/pkg/fmt/",
            "https://golang.org/pkg/os/",
        },
    },
    "https://golang.org/pkg/fmt/": &fakeResult{
        "Package fmt",
        []string{
            "https://golang.org/",
            "https://golang.org/pkg/",
        },
    },
    "https://golang.org/pkg/os/": &fakeResult{
        "Package os",
        []string{
            "https://golang.org/",
            "https://golang.org/pkg/",
        },
    },
}
  • Where next?

Go [[ https://go-zh.org/doc/ ] [document]] is an excellent start.
It contains reference guides, videos and much more information.

Learn how to organize Go code and working on it, see [[ https://www.youtube.com/watch?v=XCsL89YtqCs ] [This video]], or read [[ https://go-zh.org/ DOC / code.html ] [how to write Go Code]].

If you need help with the standard library, please refer to [[ https://go-zh.org/pkg/ ] [package manual]]. If it is the language itself helps, read [[ https://go-zh.org/ref/spec ] [language specification]] is a pleasant thing.

Go further explore the concurrency model, see [https://www.youtube.com/watch?v=f6kdp27TYZs][Go concurrency model] and [https://www.youtube.com/watch?v=QDDwwePbDtw] [depth Go concurrency model] and read [[ https://go-zh.org/doc/codewalk/sharemem/ ] [via shared memory communication]] code journey.

Want to start writing Web applications, see [https://vimeo.com/53221558] [a simple programming environment] and read [[ https://go-zh.org/doc/articles/wiki/ ] [write Web applications]] guide.

[[ Https://go-zh.org/doc/codewalk/functions/ ] [Function: Go first class citizen]] shows interesting function types.

[[ Https://blog.go-zh.org/ ] [Go blog]] has numerous articles and information on Go's.

[[ Https://www.mikespook.com/tag/golang/ ] [mikespook's blog]] There are a large number of Chinese and translated articles on Go's.

Open source e-book [[ https://github.com/astaxie/build-web-application-with-golang ] [Go Web programming]] and [[ https://github.com/Unknwon/the-way-to- go_ZH_CN ] [Go Getting Started Guide]] can help you learn more in-depth understanding and Go language.

Visit [[ https://go-zh.org ] [go-zh.org]] to learn more.

Guess you like

Origin www.cnblogs.com/pdev/p/10936485.html