<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 6.9 系統監控 我們已經完整分析過調度器的調度執行了。 當我們通過`runtime.newproc`創建好主 Goroutine 后,會將其加入到一個 P 的本地隊列中。 隨著`runtime.mstart`啟動調度器,主 Goroutine 便開始得以調度。 ``` // src/runtime/proc.go // 主 Goroutine func main() { (...) // 啟動系統后臺監控(定期垃圾回收、并發任務調度) systemstack(func() { newm(sysmon, nil) }) (...) } ``` 那么是時候看看主 Goroutine 中的系統監控`newm(sysmon, nil)`到底在干什么了。 ## 6.9.1 監控循環 ``` // 系統監控在一個獨立的 m 上運行 // 總是在沒有 P 的情況下運行,因此不能出現寫屏障 //go:nowritebarrierrec func sysmon() { lock(&amp;sched.lock) // 不計入死鎖的系統 m 的數量 sched.nmsys++ // 死鎖檢查 checkdead() unlock(&amp;sched.lock) idle := 0 // 沒有 wokeup 的周期數 delay := uint32(0) for { if idle == 0 { // 每次啟動先休眠 20us delay = 20 } else if idle &gt; 50 { // 1ms 后就翻倍休眠時間 delay *= 2 } if delay &gt; 10*1000 { // 增加到 10ms delay = 10 * 1000 } // 休眠 usleep(delay) now := nanotime() next := timeSleepUntil() // 如果在 STW,則暫時休眠 if debug.schedtrace &lt;= 0 &amp;&amp; (sched.gcwaiting != 0 || atomic.Load(&amp;sched.npidle) == uint32(gomaxprocs)) { lock(&amp;sched.lock) if atomic.Load(&amp;sched.gcwaiting) != 0 || atomic.Load(&amp;sched.npidle) == uint32(gomaxprocs) { if next &gt; now { atomic.Store(&amp;sched.sysmonwait, 1) unlock(&amp;sched.lock) // 確保 wake-up 周期足夠小從而進行正確的采樣 sleep := forcegcperiod / 2 if next-now &lt; sleep { sleep = next - now } shouldRelax := sleep &gt;= osRelaxMinNS if shouldRelax { osRelax(true) } notetsleep(&amp;sched.sysmonnote, sleep) if shouldRelax { osRelax(false) } now = nanotime() next = timeSleepUntil() lock(&amp;sched.lock) atomic.Store(&amp;sched.sysmonwait, 0) noteclear(&amp;sched.sysmonnote) } idle = 0 delay = 20 } unlock(&amp;sched.lock) } // 需要時觸發 libc interceptor if *cgo_yield != nil { asmcgocall(*cgo_yield, nil) } // 如果超過 10ms 沒有 poll,則 poll 一下網絡 lastpoll := int64(atomic.Load64(&amp;sched.lastpoll)) if netpollinited() &amp;&amp; lastpoll != 0 &amp;&amp; lastpoll+10*1000*1000 &lt; now { atomic.Cas64(&amp;sched.lastpoll, uint64(lastpoll), uint64(now)) list := netpoll(0) // 非阻塞,返回 Goroutine 列表 if !list.empty() { // 需要在插入 g 列表前減少空閑鎖住的 m 的數量(假裝有一個正在運行) // 否則會導致這些情況: // injectglist 會綁定所有的 p,但是在它開始 M 運行 P 之前,另一個 M 從 syscall 返回, // 完成運行它的 G ,注意這時候沒有 work 要做,且沒有其他正在運行 M 的死鎖報告。 incidlelocked(-1) injectglist(&amp;list) incidlelocked(1) } } if next &lt; now { // There are timers that should have already run, // perhaps because there is an unpreemptible P. // Try to start an M to run them. startm(nil, false) } // 搶奪在 syscall 中阻塞的 P、運行時間過長的 G if retake(now) != 0 { idle = 0 } else { idle++ } // 檢查是否需要強制觸發 GC if t := (gcTrigger{kind: gcTriggerTime, now: now}); t.test() &amp;&amp; atomic.Load(&amp;forcegc.idle) != 0 { lock(&amp;forcegc.lock) forcegc.idle = 0 var list gList list.push(forcegc.g) injectglist(&amp;list) unlock(&amp;forcegc.lock) } (...) } } ``` 系統監控在運行時扮演的角色無需多言, 因為使用的是運行時通知機制,在 Linux 上由 Futex 實現,不依賴調度器, 因此它自身通過`newm`在一個 M 上獨立運行, 自身永遠保持在一個循環內直到應用結束。休眠有好幾種不同的休眠策略: 1. 至少休眠 20us 2. 如果搶占 P 和 G 失敗次數超過五十、且沒有觸發 GC,則說明很閑,翻倍休眠 3. 如果休眠翻倍時間超過 10ms,保持休眠 10ms 不變 休眠結束后,先觀察目前的系統狀態,如果正在進行 GC,那么繼續休眠。 這時的休眠會被設置超時。 如果沒有超時被喚醒,則說明 GC 已經結束,一切都很好,繼續做本職工作。 如果超時,則無關 GC,必須開始進行本職善后: 1. 如果 cgo 調用被 libc 攔截,繼續觸發起調用 2. 如果已經有 10ms 沒有 poll 網絡數據,則 poll 一下網絡數據 3. 搶占在系統調用中阻塞的 P 已經運行時間過長的 G 4. 檢查是不是該觸發 GC 了 5. 如果距離上一次堆清理已經超過了兩分半,則執行清理工作 其中的`note`同步機制`retake`搶占已在[6.8 協作與搶占](https://golang.design/under-the-hood/zh-cn/part2runtime/ch06sched/preemption)和[6.8 同步原語](https://golang.design/under-the-hood/zh-cn/part2runtime/ch06sched/sync)中詳細討論過了。 ## 6.9.2 小結 總的來說系統監控的本職工作還是比較明確的,它在一個單獨的 M 上執行,負責處理網絡數據、搶占 P/G、觸發 GC、清理堆 span。 對于這些職責,我們需要確定一些細節工作: 2. `gcTrigger`如何觸發 GC?在[垃圾回收器:初始化](https://golang.design/under-the-hood/zh-cn/part2runtime/ch08gc/init)一節中詳細討論。 3. `scavenge`如何清理堆 span? 4. `netpoll`如何 poll 網絡數據? 5.
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看