Go concurrent
Go
language supports concurrency, we just need to pass the go
keyword to open goroutine
that’s it.
goroutine
is a lightweight thread, and the scheduling of goroutine
is determined by the Golang
managed at run time.
goroutine
syntax format:
Go function name (parameter list)
For example:
go f(x, y, z)
Open a new goroutine
:
f(x, y, z)
Go
allow to use go
statement to start a new runtime thread, that is, goroutine
with a different, newly created goroutine
to execute a function. Everything in the same program goroutine
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 and you will see the output hello
and world
, there is no fixed order. Because they’re two goroutine
in the execution:
world
hello
hello
world
world
hello
hello
world
world
hello
Channel
A channel is a data structure used to transmit data.
The channel can be used for two goroutine
run and communicate synchronously by passing a value of a specified type between. Operator <-
used to specify the direction of the channel, send or receive. A two-way channel if no direction is specified.
ch <- v // Send v to channel ch
v := <-ch // Receive data from ch
// And assign the value to v
Declaring a channel is simple, and we use the chan
keyword, and the channel must be created before it is used:
ch := make(chan int)
Note: by default, channels do not have buffers. The sender sends data, and there must be corresponding received data at the receiving end.
The following example uses two goroutine
to calculate the sum of the numbers, in goroutine
when the calculation is complete, it calculates 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 // Send sum to channel 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 // Received from channel c
fmt.Println(x, y, x+y)
}
The output is as follows:
-5 17 12
Channel buffer
The channel can set a buffer through the make
specifies the buffer sizeas the second parameter:
ch := make(chan int, 100)
The channel with buffer allows the data sent by the sender and the data acquisition by the receiver to be in an asynchronous state, that is, the data sent by the sender can be placed in the buffer and can wait for the receiver to obtain the data. Instead of needing the receiver to get the dataimmediately.
However, because the size of the buffer is limited, there must be a receiverto receive the data, otherwise the buffer is full and the data sender can no longer send data.
Note: if the channel is not buffered, the sender blocks until the receiver receives the value from the channel. If the channel is buffered, the sender blocks until the sent value is copied into the buffer; if the buffer is full, it means you need to wait until a receiver gets a value. The receiver blocks until it has a value to receive.
Example
package main
import "fmt"
func main() {
// Here we define a buffered channel that can store integer types
// The buffer size is 2
ch := make(chan int, 2)
// Because ch is a buffered channel, we can send two data simultaneously
// Without the need to synchronize data reading immediately
ch <- 1
ch <- 2
// Obtain these two data
fmt.Println(<-ch)
fmt.Println(<-ch)
}
The output of the execution is:
1
2
Go ergodic and closed channel
Go
pass through range
keyword to traverse the read data, similar toan array or slice. The format is as follows:
v, ok := <-ch
If the channel cannot receive the data, ok
just for false
at whichpoint the channel can be used close()
function to close.
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)
// The range function traverses each data received from the channel,
as c completes sending 10
// After the data, the channel was closed, so here our range function receives 10
data
// And then it ended. If the c channel above is not closed,
then the range function will not
// It will end, thus blocking when receiving the 11th data.
for i := range c {
fmt.Println(i)
}
}
The output of the execution is:
0
1
1
2
3
5
8
13
21
34