This is a creation in
Article, where the information may have evolved or changed.
A few days ago the small partners found that the code written six months ago there is a concurrency bug. Recall, Golang concurrency this side of the knowledge really forget almost, intend to write two notes to record. There are two main types of concurrency in Golang, one is to use Goroutine (similar to a thread) and to implement inter-thread communication through the channel, and the other through shared variables. Let's take a look at the first kind
Goroutine
First, let's look at a goroutine example.
func main (){ go func() { for i := 0; i < 10; i++ { fmt.Println("foo", i) } }() fmt.Println("bar")}
The Go foo above () opens a new goroutine, but it doesn't run out (maybe run one or two loops), because main exits first, and the whole program ends. In order for it to run, we can make main wait for it.
var wg sync.WaitGroupfunc main (){ wg.Add(1) go func() { defer wg.Done() for i := 0; i < 10; i++ { fmt.Println("foo", i) } }() fmt.Println("bar") wg.Wait()}
To show that they are concurrent, we open a few more goroutine to see if their output is out of order.
var wg sync.WaitGroupfunc foo(s string){ defer wg.Done() for i := 0; i < 10; i++ { fmt.Println(s, i) }}func main (){ wg.Add(3) go foo("foo") go foo("oof") go foo("bar") wg.Wait()}
Interested students can see how net/http is using Goroutine's
Channels
"If Goroutines is the activities of a concurrent go program, channels is the connections between them"
This sentence is the best explanation for the channel. The channel is used to pass values between Goroutine, which is a way of communicating between threads.
ch := make(chan int) //创建一个unbuffered channelch := make(chan int, 3) //创建一个buffered channel,容量为3ch <- x //发送值到channelx = <- ch //从channel中取出值<- ch //取值并丢弃close(ch) //关闭channel
The syntax is too simple! These days, even programming languages have to be materialized!
Unbuffered Channel
Sending data to the Unbuffered channel blocks the sent Goroutine until a thread receives the value of the channel. And if a goroutine tries to fetch a value on a channel that has no value, it will also be blocked until the channel is sent a value.
func main() { c := make(chan int) go func(c chan int) { time.Sleep(3 * time.Second) fmt.Println("before received") fmt.Println(<- c) }(c) c <- 1 fmt.Println("after received")}
Running the above code we see clearly that before the value in the channel is read, main is blocked until the channel is read and main continues to run.
func main() { c := make(chan int) go func(c chan int) { fmt.Println(<- c) fmt.Println("after received") }(c) time.Sleep(3 * time.Second) fmt.Println("before sending") c <- 1 time.Sleep(1 * time.Second)}
In the above code, the newly opened Goroutine first reads the channel, but because there is no value in the channel, it is blocked until the value is sent to the channel in Main, and Goroutine gets the value it wants and continues to run.
Close Channel
After the transmission is complete, the channel can be closed, all writes to the channel will be panic, and the read operation can still proceed, and when all the values are read, continue reading the channel will get zero value
func main() { naturals := make(chan int) squares := make(chan int) go func() { for x := 0; x < 100 ;x++ { naturals <- x } close(naturals) }() go func() { for x := range naturals{ squares <- x * x } close(squares) }() for x := range squares{ fmt.Println(x) }}
Buffered channels
Buffered channels is a finite long queue, let's create a buffered with a capacity of 3 channels
bc := make(chan int, 3)
If the BC has three values that have not been read, the program will go wrong if you continue to send it inside. We can use the CAP function and the Len function to check the capacity of the BC and there are now several values in it.