<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智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] ## 4、Go是否可以無限go? 如何限定數量? ### 一、不控制goroutine數量引發的問題 我們都知道Goroutine具備如下兩個特點 * 體積輕量 * 優質的GMP調度 那么goroutine是否可以無限開辟呢,如果做一個服務器或者一些高業務的場景,能否隨意的開辟goroutine并且放養不管呢?讓他們自生自滅,畢竟有強大的GC和優質的調度算法支撐? 那么我可以先看如下一個問題。 > code1.go ```go package main import ( "fmt" "math" "runtime" ) func main() { //模擬用戶需求業務的數量 task_cnt := math.MaxInt64 for i := 0; i < task_cnt; i++ { go func(i int) { //... do some busi... fmt.Println("go func ", i, " goroutine count = ", runtime.NumGoroutine()) }(i) } } ``` 結果 <img src="./pic/147-goroutines1.png" alt="image-20200328231947588" style="zoom:50%;" /> 最后被操作系統以kill信號,強制終結該進程。 ```bash signal: killed ``` 所以,我們迅速的開辟goroutine(**不控制并發的 goroutine 數量** )會在短時間內占據操作系統的資源(CPU、內存、文件描述符等)。 - CPU 使用率浮動上漲 - Memory 占用不斷上漲。 - 主進程崩潰(被殺掉了) 這些資源實際上是所有用戶態程序共享的資源,所以大批的goroutine最終引發的災難不僅僅是自身,還會關聯其他運行的程序。 所以在編寫邏輯業務的時候,限制goroutine是我們必須要重視的問題。 --- ### 二、一些簡單方法控制goroutines數量 #### 方法一:只是用有buffer的channel來限制 > code2.go ```go package main import ( "fmt" "math" "runtime" ) func busi(ch chan bool, i int) { fmt.Println("go func ", i, " goroutine count = ", runtime.NumGoroutine()) <-ch } func main() { //模擬用戶需求業務的數量 task_cnt := math.MaxInt64 //task_cnt := 10 ch := make(chan bool, 3) for i := 0; i < task_cnt; i++ { ch <- true go busi(ch, i) } } ``` 結果 ```bash ... go func 352277 goroutine count = 4 go func 352278 goroutine count = 4 go func 352279 goroutine count = 4 go func 352280 goroutine count = 4 go func 352281 goroutine count = 4 go func 352282 goroutine count = 4 go func 352283 goroutine count = 4 go func 352284 goroutine count = 4 go func 352285 goroutine count = 4 go func 352286 goroutine count = 4 go func 352287 goroutine count = 4 go func 352288 goroutine count = 4 go func 352289 goroutine count = 4 go func 352290 goroutine count = 4 go func 352291 goroutine count = 4 go func 352292 goroutine count = 4 go func 352293 goroutine count = 4 go func 352294 goroutine count = 4 go func 352295 goroutine count = 4 go func 352296 goroutine count = 4 go func 352297 goroutine count = 4 go func 352298 goroutine count = 4 go func 352299 goroutine count = 4 go func 352300 goroutine count = 4 go func 352301 goroutine count = 4 go func 352302 goroutine count = 4 ... ``` 從結果看,程序并沒有出現崩潰,而是按部就班的順序執行,并且go的數量控制在了3,(4的原因是因為還有一個main goroutine)那么從數字上看,是不是在跑的goroutines有幾十萬個呢? ![](https://img.kancloud.cn/d2/3c/d23c56981e967342ce1bff7f0c7668ce_1920x1080.jpeg) 這里我們用了,buffer為3的channel, 在寫的過程中,實際上是限制了速度。限制的是 ```go for i := 0; i < go_cnt; i++ { //循環速度 ch <- true go busi(ch, i) } ``` `for`循環的速度,因為這個速度決定了go的創建速度,而go的結束速度取決于 `busi()`函數的執行速度。 這樣實際上,我們就能夠保證了,同一時間內運行的goroutine的數量與buffer的數量一致。從而達到了限定效果。 但是這段代碼有一個小問題,就是如果我們把go_cnt的數量變的小一些,會出現打出的結果不正確。 ```go package main import ( "fmt" //"math" "runtime" ) func busi(ch chan bool, i int) { fmt.Println("go func ", i, " goroutine count = ", runtime.NumGoroutine()) <-ch } func main() { //模擬用戶需求業務的數量 //task_cnt := math.MaxInt64 task_cnt := 10 ch := make(chan bool, 3) for i := 0; i < task_cnt; i++ { ch <- true go busi(ch, i) } } ``` 結果 ```bash go func 2 goroutine count = 4 go func 3 goroutine count = 4 go func 4 goroutine count = 4 go func 5 goroutine count = 4 go func 6 goroutine count = 4 go func 1 goroutine count = 4 go func 8 goroutine count = 4 ``` 是因為`main`將全部的go開辟完之后,就立刻退出進程了。所以想全部go都執行,需要在main的最后進行阻塞操作。 #### 方法二:只使用sync同步機制 > code3.go ```go import ( "fmt" "math" "sync" "runtime" ) var wg = sync.WaitGroup{} func busi(i int) { fmt.Println("go func ", i, " goroutine count = ", runtime.NumGoroutine()) wg.Done() } func main() { //模擬用戶需求業務的數量 task_cnt := math.MaxInt64 for i := 0; i < task_cnt; i++ { wg.Add(1) go busi(i) } wg.Wait() } ``` 很明顯,單純的使用`sync`依然達不到控制goroutine的數量,所以最終結果依然是崩潰。 結果 ```bash ... go func 7562 goroutine count = 7582 go func 24819 goroutine count = 17985 go func 7685 goroutine count = 7582 go func 24701 goroutine count = 17984 go func 7563 goroutine count = 7582 go func 24821 goroutine count = 17983 go func 24822 goroutine count = 17983 go func 7686 goroutine count = 7582 go func 24703 goroutine count = 17982 go func 7564 goroutine count = 7582 go func 24824 goroutine count = 17981 go func 7687 goroutine count = 7582 go func 24705 goroutine count = 17980 go func 24706 goroutine count = 17980 go func 24707 goroutine count = 17979 go func 7688 goroutine count = 7582 go func 24826 goroutine count = 17978 go func 7566 goroutine count = 7582 go func 24709 goroutine count = 17977 go func 7689 goroutine count = 7582 go func 24828 goroutine count = 17976 go func 24829 goroutine count = 17976 go func 7567 goroutine count = 7582 go func 24711 goroutine count = 17975 //操作系統停止響應 ``` #### 方法三:channel與sync同步組合方式 > code4.go ```go package main import ( "fmt" "math" "sync" "runtime" ) var wg = sync.WaitGroup{} func busi(ch chan bool, i int) { fmt.Println("go func ", i, " goroutine count = ", runtime.NumGoroutine()) <-ch wg.Done() } func main() { //模擬用戶需求go業務的數量 task_cnt := math.MaxInt64 ch := make(chan bool, 3) for i := 0; i < task_cnt; i++ { wg.Add(1) ch <- true go busi(ch, i) } wg.Wait() } ``` 結果 ```bash //... go func 228851 goroutine count = 4 go func 228852 goroutine count = 4 go func 228853 goroutine count = 4 go func 228854 goroutine count = 4 go func 228855 goroutine count = 4 go func 228856 goroutine count = 4 go func 228857 goroutine count = 4 go func 228858 goroutine count = 4 go func 228859 goroutine count = 4 go func 228860 goroutine count = 4 go func 228861 goroutine count = 4 go func 228862 goroutine count = 4 go func 228863 goroutine count = 4 go func 228864 goroutine count = 4 go func 228865 goroutine count = 4 go func 228866 goroutine count = 4 go func 228867 goroutine count = 4 //... ``` 這樣我們程序就不會再造成資源爆炸而崩潰。而且運行go的數量控制住了在buffer為3的這個范圍內。 #### 方法四:利用無緩沖channel與任務發送/執行分離方式 > code5.go ```go package main import ( "fmt" "math" "sync" "runtime" ) var wg = sync.WaitGroup{} func busi(ch chan int) { for t := range ch { fmt.Println("go task = ", t, ", goroutine count = ", runtime.NumGoroutine()) wg.Done() } } func sendTask(task int, ch chan int) { wg.Add(1) ch <- task } func main() { ch := make(chan int) //無buffer channel goCnt := 3 //啟動goroutine的數量 for i := 0; i < goCnt; i++ { //啟動go go busi(ch) } taskCnt := math.MaxInt64 //模擬用戶需求業務的數量 for t := 0; t < taskCnt; t++ { //發送任務 sendTask(t, ch) } wg.Wait() } ``` 結構 ```bash //... go task = 130069 , goroutine count = 4 go task = 130070 , goroutine count = 4 go task = 130071 , goroutine count = 4 go task = 130072 , goroutine count = 4 go task = 130073 , goroutine count = 4 go task = 130074 , goroutine count = 4 go task = 130075 , goroutine count = 4 go task = 130076 , goroutine count = 4 go task = 130077 , goroutine count = 4 go task = 130078 , goroutine count = 4 go task = 130079 , goroutine count = 4 go task = 130080 , goroutine count = 4 go task = 130081 , goroutine count = 4 go task = 130082 , goroutine count = 4 go task = 130083 , goroutine count = 4 go task = 130084 , goroutine count = 4 go task = 130085 , goroutine count = 4 go task = 130086 , goroutine count = 4 go task = 130087 , goroutine count = 4 go task = 130088 , goroutine count = 4 go task = 130089 , goroutine count = 4 go task = 130090 , goroutine count = 4 go task = 130091 , goroutine count = 4 go task = 130092 , goroutine count = 4 go task = 130093 , goroutine count = 4 ... ``` 執行流程大致如下,這里實際上是將任務的發送和執行做了業務上的分離。使得消息出去,輸入SendTask的頻率可設置、執行Goroutine的數量也可設置。也就是既控制輸入(生產),又控制輸出(消費)。使得可控更加靈活。這也是很多Go框架的Worker工作池的最初設計思想理念。 ![](https://img.kancloud.cn/6a/77/6a77f3dfeee80f074b120fd34c96137e_1920x1080.jpeg) --- 以上便是目前有關限定goroutine基礎設計思路。 參考: http://team.jiunile.com/blog/2019/09/go-control-goroutine-number.html https://www.joyk.com/dig/detail/1547976674512705
                  <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>

                              哎呀哎呀视频在线观看