Golang study notes: goroutine

1.goroutine

A goroutine is a concurrent body of the go language. In the go language, the go keyword can be used to achieve concurrency.

go func()

1.1 Concept introduction

Goroutines are essentially coroutines. When I was just learning, I roughly thought that goroutines were threads, and only recently began to understand the basic concepts of goroutines.

Concurrency

A long time ago, people hoped that a computer (a cpu) could perform multiple tasks at the same time, let the cpu split for a certain period of time, execute program a in a very short period of time, and then quickly switch to program b To execute, to make it look like two programs are running at the same time, this is concurrency .

process

But people found that when the CPU switches programs, if it does not save the state of the previous program (that is, the context we often say), and directly switches the next program, it will lose a series of states of the previous program. , so the concept of process is introduced to divide the resources required by the program to run. Therefore, a process is the basic resource unit required for a program to run (it can also be said to be an entity for the program to run).

parallel

If a computer has multiple CPUs and each CPU has a process running, this is parallelism.

User Mode and Kernel Mode

In order to prevent the user program from making some dangerous instructions, such as shutting down, changing system variables, and modifying other process data, the system is divided into two operating states, user state and kernel state. Operates on the underlying layers of the kernel. If we need to use the underlying operations of the kernel, the kernel provides an interface to call the kernel. We call these interfaces, which are also system calls. When making a system call, the cpu will switch to the kernel mode to execute the functions of the kernel.

thread

People found another problem. When the CPU switches multiple processes, it will take a lot of time, because switching processes needs to switch to the kernel state, and each time the scheduling needs the kernel state, it needs to read the data of the user state. Once there are more processes , CPU scheduling will consume a lot of resources, so the concept of threads is introduced. Threads hardly occupy resources. They share resources in the process. Kernel scheduling will not be as resource-intensive as process switching.

coroutine

However, the thread still needs the kernel to be scheduled. When switching, it also needs to write the user-mode data to the kernel-mode, which also requires a certain amount of computer resources. Can we change the switching scheduling to our own control? The answer is Yes, the coroutine is to hand over its own scheduling algorithm to the program (user mode) for management, and can perform concurrency with smaller resources.

image

A goroutine is an example of a coroutine, which can be scheduled according to its own scheduler. When a gooutine calls the time.sleep method or channel and the mutex is blocked, the scheduler will put it to sleep and wake up another goroutine without entering the kernel at all. state.

2. Communication

A goroutine is essentially a coroutine, which can be understood as a thread that is not scheduled by the kernel but managed by the go scheduler. Goroutines can communicate through channels, as follows:

func main() {
    c := make(chan string)
    go func(){
        c <- "hello"
    }()
    
    go func(){
       word := <- c + " world"
       fmt.Println(word)
    }()
    time.Sleep(1 * time.Second)
}

3. Safe Exit

The goroutine will only be interrupted when its own function finishes running, or the main function finishes running, so the above example needs to wait for one second, otherwise the unexecuted goroutine will be interrupted directly. If we have a large number of concurrent threads, it is impossible for us to set an accurate sleep time in main to evaluate that all goroutines have finished running and then exit.
At this time, we can use sync.WaitGroup to wait for all running goroutines to finish running, and then exit the main function. The main principle is to maintain a counter of the number of goroutines. Every time a goroutine runs, the counter will increase by +1. -1, then calling the wait method will block all the time until the counter is 0, that is, the number of goroutines currently running is 0. The example is as follows:

func main() {
    var n sync.WaitGroup
    for i:= 0; i < 20; i++ {
        n.Add(1)
        go func(){
            defer n.Done()
            time.Sleep(i * time.Second)
            fmt.Println("goroutine" + i + "is running")
        }()
    }
    n.Wait()
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324892796&siteId=291194637