SoFunction
Updated on 2025-03-04

Detailed explanation of concurrency in Go language

1. Start the Go language coroutine

package main
 
import (
    "fmt"
    "runtime"
)
 
//runtime package 
func main() {
    //() is used to give up the CPU time slice, give up the CPU time slice, and let the scheduler reassign resources 
    //Write an anonymous function    s := "test"
    go func(s string) {
        for i :=0;i <2;i++ {
            (s)
        }
    }(s)
 
    for i :=0;i <2;i ++ {
        //If the code runs here, the scheduler will release the CPU resources and let the scheduler reassign the CPU resources. It can be allocated to the child coroutine or the main coroutine        ()
        ("123")
    }
}

2. () method. Terminate the current coroutine immediately

package main
 
import (
    "fmt"
    "runtime"
    "time"
)
 
//()    immediately terminate the current coroutinefunc main() {
    go func() {
        defer ("")
        func () {
            defer ("")
            //End the current coroutine immediately, the function will go through the defer process            ()
            ("B")
        }()
        ("A")
    }()
    for {
        (2 * )
    }
}
 
//Result without adding ()//B
//
//A
//
 
//The result of adding()//
//

3. () means that go uses several CPUs to execute code

package main
 
import (
    "fmt"
    "runtime"
)
 
func main() {
    //() means to let go with several CPUs to do the following things    n := (4)
    ("%T--->%p---%d\n",n,n,n)
    for {
        go ("0")
        (1)
    }
}

4. Pipeline definition and creation

package main
 
import "fmt"
 
//The coroutines of the go language run in the same address space, so accessing shared memory must be synchronized and thread safety issues must be handled well 
//The communication between coroutines in the go language is shared by communicating between coroutines, rather than sharing memory. 
//Channel is a reference type, used for communication between multiple coroutines, and synchronizes internally to ensure concurrency security 
 
//Channel is generally used in conjunction with coroutines 
 
//If there is no data in the channel and you still get the data later, you will report an error//fatal error: all goroutines are asleep - deadlock!
func main() {
    //test45_1 := make(chan int) //Define an unbuffered channel 
    //The unbuffered channel is a value that has no ability to save data before accepting data. Only one data can enter the channel. After entering the channel, the channel will be locked until the data is retrieved and the lock will be released. 
    //The unbuffered channel may block. If I send a data to the channel, but there is no coroutine to fetch the data, the first coroutine will be blocked 
    //test45_2 := make(chan int,10) //Define a buffered channel 
 
    // A buffered channel means that the channel can store a specified amount of data, and the data also has a sequence in it, but if the number of buffers is full, the channel will also be blocked. 
    //
    //test45_1 <- 10   //Send data to channel    //<- test45_1      // Accept data in the channel and discard it    //x := <-test45_1 //Take the value from the channel and assign the value to x    //x,ok := <-test45_1  //ok Check whether the channel is closed or empty 
 
    //1. Create a channel that stores type int    test45_1 := make(chan int)
 
    go func() {
        defer ("Subcord Process End")
        ("Subcord process is running")
 
        test45_1 &lt;- 111
    }()
    //&lt;- test45_1
    //The master coroutine fetches data from the channel    x := &lt;- test45_1
    (x)
    ("Main coroutine ends")
}

5. Pipeline buffering

package main
 
import (
    "fmt"
    "time"
)
 
func main() {
    //If there is no buffering channel, the length is 0. If there is a buffering channel, it is 0. If there is a buffering channel, it is 0.    test46_1 := make(chan int,0)
 
    //%P is the print memory address, and %T is the type of print variable    //("Length:%d--->Capacity:%d--->%P----%T",len(test46_1),cap(test46_1),test46_1,test46_1) 
    go func() {
        defer ("Subcord Process End")
 
        for i :=0;i &lt; 3;i ++ {
            ("Subcord process inserts data")
            test46_1 &lt;- i
            //("Length:%d--->Capacity:%d--->%P----%T",len(test46_1),cap(test46_1),test46_1,test46_1) 
        }
 
    }()
 
    (2 * )
    for j :=0;j &lt;3;j++ {
        ("Main coroutine fetch data")
        num := &lt;- test46_1
        (num)
    }
}

6. Close the pipeline and receive signals to close the pipeline

package main
 
import "fmt"
 
//close() method, meaning to close the channel 
func main() {
    test47_1 := make(chan int,4)
 
    go func() {
        for i :=0;i &lt; 10;i ++ {
            test47_1 &lt;- i
        }
        //This means closing the channel test47_1        close(test47_1)
    }()
 
    //For writing, traverse the channel    //for {
    //  // The subcoroutine closes the channel, and you can receive it here if you have ok. Here you can go to the bread process. The ok parameter indicates whether the channel is closed    //  if data,ok := &lt;- test47_1;ok {
    //      (data)
    //  }else {
    //      break
    //  }
    //}
 
    //The writing method of range, traverse the channel    for data := range test47_1 {
        (data)
    }
    ("Main coroutine ends")
}

7. Read-only pipeline and write-only pipeline and producer and consumer models

package main
 
import (
    "fmt"
    "time"
)
 
//By default, the pipeline is bidirectional, and can both write and read data.  Go can also define a single-direction pipeline, that is, only send data, or only write data. 
//Binocular pipelines can be converted into unidirectional pipelines, but unidirectional pipelines cannot be converted into bidirectional pipelines 
//One-directional pipeline 
func producter(out chan &lt;- int)  {
    defer close(out)
    for i := 0;i &lt; 10;i++ {
        out &lt;- i
    }
 
}
 
func consumer(int &lt;-chan int){
    for num := range int {
        (num)
    }
}
func main() {
 
    //1. Define the pipeline    //Define a normal pipeline    //var test48_1 chan int
 
    //Define a one-way write-only pipeline    //var test48_2 chan &lt;- float32
 
    //Define a one-way read-only pipeline    //var test48_3 &lt;- chan int
 
    //2. Convert pipeline 
    //Convert normal pipes to write-only or read-only pipes    //Define a normal pipeline    //test48_4 := make(chan int,3)
 
    //Convert a normal pipeline to a write-only pipeline    //var write_only chan &lt;- int = test48_4
 
    //Convert a normal pipeline to a read-only pipeline    //var read_only &lt;- chan int = test48_4
 
 
 
    test48_5 := make(chan int,4)
 
    //Start the producer    go producter(test48_5)
 
    //Start the consumer    consumer(test48_5)
 
    (10 * )
    ("down")
 
}

8. Timer timer

package main
 
import (
    "fmt"
    "time"
)
 
//Timer 
//().  Time is up, only once//(), periodic execution 
func main() {
    //1. Create a timer. After 2s, the timer will save a time to a C    test49_1 := (2 * )
 
    //Print the current time of the system 
    t1 := ()
 
    ("t1-----&gt;%v\n",t1)
 
    //Print from the pipe 
    t2 := &lt;- test49_1.C
    ("t2-----&gt;%v\n",t2)
 
 
 
    //2. Proof that timer is only executed once    //test49_2 := (4 * )
    //
    //for {
    //  c := &lt;- test49_2.C
    //  (c)
    //}
 
    //3. Implement a delay function through timer 
    //Method 1    //(2 * )
 
    //Method 2    //test49_3 := (2 * )
 
    //Method 3 
    //&lt;-(2 *)
 
    //4. Stop the timer    test49_4 := (4 * )
    //Subcord    go func() {
        //This means that data can only be retrieved after 3s        &lt;- test49_4.C
 
        ("Timer time has arrived")
    }()
 
    //Switch off the timer    stop := test49_4.Stop()
    if stop {
        ("Timer has been closed")
    }
 
    //5. Reset the timer    test49_5 := (4 * )
    //Reset the timer to 1s    test49_5.Reset(1 * )
 
    for {
 
    }
    }

9. Ticker timer and shut down the ticker timer

package main
 
import (
    "fmt"
    "time"
)
 
//(), timer, response multiple times 
func main() {
    //Create a timer with 1s interval    test50_1 := ()
    i := 0
    go func() {
        for {
            c := &lt;- test50_1.C
            (c)
            i ++
            (i)
        }
        }()
 
 
    for {
 
    }
}

10. Select statement

package main
 
import (
    "fmt"
)
 
//Go language provides the select keyword to monitor data flow on the channel. The syntax is similar to switch. The difference is that select must require that each case statement must have an IO operation. 
//If all can match, select a channel to run randomly. Select is more casual. 
func main() {
    //test51_1 := make(chan int,3)
    //select {
    //case &lt;- test51_1:
    //  ("jja")
    //// If data can be read from the channel, then execute this    //case test51_1 &lt;- 1:
    //  ("aa")
    //// If data is written in the north of the channel, the execution number is here    //default:
    //  ("hah")
    //// If none of the above succeeds, then execute here    //}
 
 
    test51_1 := make(chan int,1)
    test51_2 := make(chan string,1)
 
    go func() {
        //(2 * )
        test51_1 &lt;- 1
 
    }()
    go func() {
        test51_2 &lt;- "Hello World"
    }()
 
    select {
    case Value1:= &lt;- test51_1:
        (Value1)
    case Value2 := &lt;- test51_2:
        (Value2)
    }
    ("Finish")
 
}

11. Coroutine synchronization lock

package main
 
import (
    "fmt"
    "sync"
    "time"
)
 
//Go language coroutine synchronization lock solves concurrency security issues 
 
//Example of withdrawal 
type Account struct {
    money int
    flag 
}
 
func Check(a *Account)  {
    (1 * )
}
 
func (a *Account)SetAccount(n int)  {
     = n
}
 
func (a *Account)GetAccount() (n int) {
    return 
}
 
func (a *Account) buy1(n int)  {
    ()
    if  &gt; n {
        Check(a)
         -= n
    }
    ()
    ()
}
 
 
func (a *Account) buy2(n int)  {
    ()
    if  &gt; n {
        Check(a)
         -= n
    }
    ()
    ()
}
 
func main() {
    var test52_1 Account
    test52_1.SetAccount(10)
 
    go test52_1.buy1(5)
    go test52_1.buy2(6)
    for {
 
    }
}

12、wait

We implement wait ourselves

package main
 
import "fmt"
//Add() count is added by 1//Done() count down by 1//Wait() main function callfunc main() {
    test53_1 := make(chan int,2)
    count := 2
    go func() {
        ("Subcord 1")
        test53_1 &lt;- 1
    }()
    go func() {
        ("Subcord 2")
        test53_1 &lt;- 2
    }()
 
    for range test53_1 {
        count --
        if count == 0 {
            ("All subcoroutines have ended")
            close(test53_1)
        }
    }
}

Go language implements wait for us

package main
 
import (
    "fmt"
    "sync"
)
//Add() count is added by 1//Done() count down by 1//Wait() main function callfunc main() {
 
    var wait_group 
 
    //This is the number of subcoroutines    wait_group.Add(2)
    //test54_1 := make(chan int,2)
 
    go func() {
        ("Subcord 1")
        wait_group.Done()
    }()
    go func() {
        ("Subcord 2")
        wait_group.Done()
    }()
 
 
    wait_group.Wait()
    //close(test53_1)
    ("All child coroutines end")
 
}

The above is a detailed explanation of the concurrency of Go. For more information about concurrency of Go, please pay attention to my other related articles!