Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What happens to one of the dead loops when a single-core CPU opens two Goroutine in Go language

2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article shows you how one of the endless loops in Go when a single-core CPU opens two Goroutines. The content is concise and easy to understand. It will definitely make your eyes shine. I hope you can gain something through the detailed introduction of this article.

Today's hero, is with Go engineers have scheduling related knowledge, that is,"single-core CPU, open two Goroutines, one of which endless loop, what will happen?" "

Please recite the answer in your mind here, and then go to discuss a wave of Go technical philosophy with fried fish.

problem definition

To solve this problem, we need to split the problem and see that it has the following elements:

The computer running Go has only a single CPU. Two goroutines are running. A Goroutine endless loop.

According to the meaning of this question, it can be roughly understood that what it wants to ask is some knowledge understanding related to Go scheduling.

single-core CPU

The first point is to make clear what effect the variable definition of "computer has only one single-core CPU" will have on Go program, otherwise it will be difficult to continue to expand.

Since Goroutine is explicitly involved, this will examine your basic understanding of Go's scheduling model GMP.

From a single-core CPU point of view, the biggest impact is P in the GMP model, because the number of P is consistent with the CPU core number (GOMAXPROCS) by default.

G: Goroutine, actually every time we call go func we generate a G. P: Processor, processor, the number of P is generally the number of cores of the processor, which can be modified through GOMAXPROCS. M: Machine, system thread.

These interactions are actually derived from Go's M: N scheduling model. That is, M must bind to P, and then loop over M to find a workable G to perform the corresponding task.

Goroutine Limited

The second point is that the number and mode of operation of Goroutine are limited. There are two Goroutines, one Goroutine in a loop and the other in normal operation.

This can be understood as Main Goroutine + starting a new Goroutine running endless loop, because the main function itself is a main coroutine running, no problem.

It should be noted that Goroutine runs an endless loop, that is,"business logic" runs all the time. This block needs to be associated with a single-core CPU, considering whether it will always block and run the entire Go process to hang?

Note: But if you are interviewing on the spot, you can enumerate this scene first and explain it clearly. Ask the interviewer if this is the case.

Go version of the problem

The third point is an implicit extension point. If you're an older Go fan and keep an eye on updates to Go versions (at least big ones), you should know that Go's scheduling is subject to change (as explained in a later section).

Therefore, the problem in this article may have different results in different versions of Go. However, the interviewer did not point out that it is necessary to consider:

The interviewer deliberately does not point out, waiting for you to point out. The interviewer didn't notice this, didn't think so much. The interviewer himself does not know this piece of "new" knowledge, and his knowledge may still be old.

If you notice, it's a small bright spot, indicating that you have some accumulated knowledge in this area.

actual combat drills

In the last three seconds, you've gone through all of the above considerations in your head. Next, we formally entered the actual combat exercise and constructed an example:

// Main Goroutine

func main() {

//Analog single-core CPU

runtime.GOMAXPROCS(1)

//Simulate Goroutine loop

go func() {

for {

}

}()

time.Sleep(time.Millisecond)

fmt.Println("brain fried fish")

}

In the example above, we achieved the goal of the interview question by:

The set runtime.GOMAXPROCS method simulates a scenario where there is only one P on a single CPU. Run a Goroutine, internally run a for endless loop, to achieve the purpose of blocking the run. Running a Goroutine, the main function is itself a Main Goroutine.

Think about it: does this program output "brain fried fish" and why?

The answer is:

No results will be output until Go1.14. After Go1.14 and later, the output results can be normal. why

What's going on here, what are the causes and criteria for these two situations, and what are the effects of changes to the Go version?

No results will be output

Obviously, this program has a Goroutine that is executing an endless loop, which means it must not be preempted.

There are no calls to relinquish execution (runtime.Gosched) or other calls that might cause execution to shift. Therefore, Goroutine has no chance to slip away and can only work all the time...

Why does the Main Goroutine fail to run? In fact, the reason is that sleep will be called first, but because of the single-core CPU, it only has a unique P. The only P has been working and unwilling to leave work (execution for endless loop, forced to work indefinitely).

Therefore, the main coroutine never has a chance to schedule, so the Go program naturally blocks in the Goroutine that executes the endless loop, and can never get off work (after execution, exit the program).

normal output result

So why does Go 1.14 and later output normally again?

It is mainly in Go1.14 that signal-based preemptive scheduling is implemented to solve some of the above scenarios that still cannot be preempted.

The main principle is that Go programs, when started, register in the runtime. sieghandler method and bind SIGURG signals:

func mstartm0() {

...

initsig(false)

}

func initsig(preinit bool) {

for i := uint32(0); i < _NSIG; i++ {

...

setsig(i, funcPC(sighandler))

}

}

Bind the corresponding runtime.doSigPreempt method:

func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {

...

if sig == sigPreempt && debug.asyncpreemptoff == 0 {

//execute preemption

doSigPreempt(gp, c)

}

}

Meanwhile, the runtime.sysmon method of the scheduler calls the restore method to handle two scenarios:

Preemption blocks P on system calls. Preemption of G running too long.

The method detects P that fits the scenario and sends a signal to M when one of the two scenarios is met. M will sleep the blocking Goroutine after receiving the signal, call the bound signal method, and reschedule. To solve this problem.

Note: In Go, sysmon is used to detect preemption. sysmon is Go's Runtime system detector, sysmon can perform a series of actions such as forcec, netpoll, and retrieve (via @xiaorui).

In this article, we aim at "single-core CPU, open two Goroutines, one of which is endless loop, what happens?" "The problem was analysed.

The logic of different programs takes different forms for different versions of Go, but the underlying principles are related to Go scheduling model and preemption.

The above is what happens when a single-core CPU opens two Goroutines in Go and one of them is an endless loop. Have you learned any knowledge or skills? If you want to learn more skills or enrich your knowledge reserves, please pay attention to the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report