In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-30 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >
Share
Shulou(Shulou.com)05/31 Report--
This article will explain in detail the example analysis of Go language based on signal preemptive scheduling. The content of the article is of high quality, so the editor shares it for you as a reference. I hope you will have some understanding of the relevant knowledge after reading this article.
Introduction
Prior to the 1.14 version of Go, preemption trial scheduling is based on cooperation and needs to be executed on its own initiative, but it is impossible to deal with some edge situations that cannot be preempted. For example, for loops or garbage collection take up threads for a long time, and some of these problems are not solved by signal-based preemptive scheduling until 1.14.
Let's verify the preemption difference between version 1.14 and version 1.13 with an example:
Package mainimport ("fmt"os"runtime"runtime/trace"sync") func main () {runtime.GOMAXPROCS (1) f, _: = os.Create ("trace.output") defer f.Close () _ = trace.Start (f) defer trace.Stop () var wg sync.WaitGroup for I: = 0; I
< 30; i++ { wg.Add(1) go func() { defer wg.Done() t := 0 for i:=0;i now { continue } unlock(&allpLock) incidlelocked(-1) if atomic.Cas(&_p_.status, s, _Pidle) { n++ _p_.syscalltick++ // 让出处理器的使用权 handoffp(_p_) } incidlelocked(1) lock(&allpLock) } } unlock(&allpLock) return uint32(n)} 这一过程会判断 P 的状态如果处于 _Psyscall 状态时,会进行一个判断,有一个不满足则调用 handoffp 让出 P 的使用权: runqempty(_p_) :判断 P 的任务队列是否为空; atomic.Load(&sched.nmspinning)+atomic.Load(&sched.npidle):nmspinning 表示正在窃取 G 的数量,npidle 表示空闲 P 的数量,判断是否存在空闲 P 和正在进行调度窃取 G 的 P; pd.syscallwhen+10*1000*1000 >Now: determines whether the system call time exceeds 10ms
Go GC stack scan sends preemption signal
GC related content can see this article: "Go language GC implementation principle and source code analysis https://www.luozhiyun.com/archives/475". Go scans the stack of G when marking GC Root during GC. Before scanning, suspendG is called to suspend the execution of G before scanning. After scanning, resumeG is called again to resume execution.
The function is at: runtime/mgcmark.go:
Markroot
Func markroot (gcw * gcWork, I uint32) {... Switch {. / / scan the stack default of each G: / / get the G var gp * g if baseStacks = nextPreemptM {nextPreemptM = now + yieldDelay/2 to be scanned / / execute preemption signal to send preemptM (asyncM)}}.}}.
For the suspendG function, I only truncated the processing of G in the _ Grunning state. In this state, preemptStop is set to true, which is the only place where it is set to true. PreemptStop is related to the execution of preemption signals. Students who forget can turn to the asyncPreempt2 function above.
Go GC StopTheWorld preempts all P
Go GC STW is executed through the stopTheWorldWithSema function, which is found in runtime/proc.go:
StopTheWorldWithSema
Func stopTheWorldWithSema () {_ g _: = getg () lock (& sched.lock) sched.stopwait = gomaxprocs / / tag gcwaiting When you see this flag when scheduling, you will enter waiting for atomic.Store (& sched.gcwaiting, 1) / / send preemption signal preemptall () / / pause the current P _ g_.m.p.ptr (). Status = _ Pgcstop / / Pgcstop is only diagnostic. ... Wait: = sched.stopwait > 0 unlock (& sched.lock) if wait {for {/ / wait for 100us if notetsleep (& sched.stopnote) {noteclear (& sched.stopnote) break} / / send preemption signal preemptall ()} again.}
The stopTheWorldWithSema function calls preemptall to send a preemption signal to all P.
The file location of the preemptall function is in runtime/proc.go:
Preemptall
Func preemptall () bool {res: = false / / traverses all P for _, _ p _: = range allp {if _ p_.status! = _ Prunning {continue} / / A pair of running P sends the preemption signal if preemptone (_ p _) {res = true}} return res}
The preemptone called by preemptall will mark the G being executed in the M corresponding to P and mark it as preemptive; finally, preemptM will be called to send a preemption signal to M.
The file location of this function is in runtime/proc.go:
Preemptone
Func preemptone (_ p* p) bool {/ / get M mp for P: = _ p_.m.ptr () if mp = = nil | | mp = = getg () .m {return false} / / get G gp: = mp.curg if gp = = nil that M is executing | gp = = mp.g0 { Return false} / / Mark G as preemptive gp.preempt = true / / detect whether it is preempted during stack expansion gp.stackguard0 = stackPreempt / / request asynchronous preemption of this P if preemptMSupported & & debug.asyncpreemptoff = 0 {_ p_.preempt = true preemptM (mp)} return true}
Specific logic:
When the program starts, the handler function runtime.doSigPreempt of the _ SIGURG signal is registered
At this time, an M1 sends an interrupt signal _ SIGURG to M2 through the signalM function.
M2 receives the signal and the operating system interrupts its code execution and switches to the signal processing function runtime.doSigPreempt
M2 calls runtime.asyncPreempt to modify the context of execution, re-enter the scheduling cycle and schedule other G.
So much for the example analysis of Go language based on signal preemptive scheduling. I hope the above can be helpful to you and learn more knowledge. If you think the article is good, you can share it for more people to see.
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.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.