[Go] Go Language Tutorial--Go Concurrency (21)

Past review:

foreword

The Go language supports concurrency, we only need to start the goroutine with the go keyword.

Goroutines are lightweight threads, and the scheduling of goroutines is managed by the Golang runtime.

goroutine syntax format

go 函数名( 参数列表 

For example:

go f(x, y, z)

Start a new goroutine:

f(x, y, z)

Go allows the use of the go statement to start a new runtime thread, a goroutine, to execute a function in a different, newly created goroutine. All goroutines in the same program share the same address space.

example

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

Execute the above code, you will see that the output hello and world are in no fixed order. Because they are two goroutines executing:

world
hello
hello
world
world
hello
hello
world
world
hello

channel

A channel is a data structure used to transfer data.

Channels can be used to synchronize execution and communication between two goroutines by passing a value of a specified type. The operator <- is used to specify the direction of the channel, send or receive. If no direction is specified, it is a bidirectional channel.

ch <- v    // 把 v 发送到通道 ch
v := <-ch  // 从 ch 接收数据
           // 并把值赋给 v

Declaring a channel is very simple, we can use the chan keyword, the channel must be created before use:

ch := make(chan int)

Note: By default, channels are unbuffered. When the sender sends data, there must be corresponding data received by the receiver.

The following example computes the sum of a number through two goroutines, and after the goroutine finishes computing, it computes the sum of the two results:

example

package main

import "fmt"

func sum(s []int, c chan int) {
    
    
        sum := 0
        for _, v := range s {
    
    
                sum += v
        }
        c <- sum // 把 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)
}

The output is:

-5 17 12

channel buffer

The channel can set the buffer, and specify the buffer size through the second parameter of make:

ch := make(chan int, 100)

A channel with a buffer allows the sending of data by the sender and the acquisition of data by the receiver to be in an asynchronous state, which means that the data sent by the sender can be placed in the buffer and wait for the receiver to get the data instead of immediately requiring the receiver to get the data.

However, since the size of the buffer is limited, there must still be a receiving end to receive the data, otherwise, once the buffer is full, the data sending end will no longer be able to send data.

Note: If the channel is not buffered, the sender will block until the receiver has received a value from the channel. If the channel is buffered, the sender will block until the sent value is copied into the buffer; if the buffer is full, it means waiting until a receiver gets a value. The receiver blocks until there is a value to receive.

example

package main

import "fmt"

func main() {
    
    
    // 这里我们定义了一个可以存储整数类型的带缓冲通道
        // 缓冲区大小为2
        ch := make(chan int, 2)

        // 因为 ch 是带缓冲的通道,我们可以同时发送两个数据
        // 而不用立刻需要去同步读取数据
        ch <- 1
        ch <- 2

        // 获取这两个数据
        fmt.Println(<-ch)
        fmt.Println(<-ch)
}

The execution output is:

1
2

Go traverses channels and closes channels

Go uses the range keyword to traverse the read data, similar to arrays or slices. The format is as follows:

v, ok := <-ch

If the channel does not receive data, ok will be false, then the channel can be closed using the close() function.

example

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)
        // range 函数遍历每个从通道接收到的数据,因为 c 在发送完 10 个
        // 数据之后就关闭了通道,所以这里我们 range 函数在接收到 10 个数据
        // 之后就结束了。如果上面的 c 通道不关闭,那么 range 函数就不
        // 会结束,从而在接收第 11 个数据的时候就阻塞了。
        for i := range c {
    
    
                fmt.Println(i)
        }
}

The execution output is:

0
1
1
2
3
5
8
13
21
34

Guess you like

Origin blog.csdn.net/u011397981/article/details/131863637