1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Go并發(fā)等待

        共 4031字,需瀏覽 9分鐘

         ·

        2021-07-18 17:51

        上節(jié)答疑

        上一節(jié)有讀者問goroutine stack size一般是多大,我進行了詳細的查詢

        關于 goroutine stack size(棧內存大?。?官方的文檔 中所述,1.2 之前最小是4kb,在1.2 變成8kb,并且可以使用SetMaxStack 設置棧最大大小。

        在 runtime/debug 包能控制最大的單個 goroutine 的堆棧的大小。在 64 位系統上默認為 1GB,在 32 位系統上默認為 250MB。

        因為每個goroutine需要能夠運行,所以它們都有自己的棧。假如每個goroutine分配固定棧大小并且不能增長,太小則會導致溢出,太大又會浪費空間,無法存在許多的goroutine。

        所以在1.3版本中,改為了 Contiguous stack( 連續(xù)棧 ),為了解決這個問題,goroutine可以初始時只給棧分配很小的空間(8KB),然后隨著使用過程中的需要自動地增長。這就是為什么Go可以開千千萬萬個goroutine而不會耗盡內存。

        1.4 版本 goroutine 堆棧從 8Kb 減少到 2Kb

        Golang并發(fā)等待

        本節(jié)源碼位置 https://github.com/golang-minibear2333/golang/blob/master/4.concurrent/goroutine-wait/

        簡介

        goroutineGolang 中非常有用的功能,有時候 goroutine 沒執(zhí)行完函數就返回了,如果希望等待當前的 goroutine 執(zhí)行完成再接著往下執(zhí)行,該怎么辦?

        func say(s string) {
            for i := 0; i < 3; i++ {
                time.Sleep(100 * time.Millisecond)
                fmt.Println(s)
            }
        }

        func main() {
            go say("hello world")
            fmt.Println("over!")
        }

        輸出 over! , 主線程沒有等待

        使用 Sleep 等待

        func main() {
            go say("hello world")
            time.Sleep(time.Second*1)
            fmt.Println("over!")
        }

        運行修改后的程序,結果如下:

        hello world
        hello world
        hello world
        over!

        結果符合預期,但是太 low 了,我們不知道實際執(zhí)行中應該等待多長時間,所以不能接受這個方案!

        發(fā)送信號

        func main() {
            done := make(chan bool)
            go func() {
                for i := 0; i < 3; i++ {
                    time.Sleep(100 * time.Millisecond)
                    fmt.Println("hello world")
                }
                done <- true
            }()

            <-done
            fmt.Println("over!")
        }

        輸出的結果和上面相同,也符合預期

        這種方式不能處理多個協程,所以也不是優(yōu)雅的解決方式。

        WaitGroup

        Golang 官方在 sync 包中提供了 WaitGroup 類型可以解決這個問題。其文檔描述如下:

        使用方法可以總結為下面幾點:

        • 在父協程中創(chuàng)建一個 WaitGroup 實例,比如名稱為:wg
        • 調用 wg.Add(n) ,其中 n 是等待的 goroutine 的數量
        • 在每個 goroutine 運行的函數中執(zhí)行 defer wg.Done()
        • 調用 wg.Wait() 阻塞主邏輯
        • 直到所有 goroutine 執(zhí)行完成。
        func main() {
            var wg sync.WaitGroup
            wg.Add(2)
            go say2("hello", &wg)
            go say2("world", &wg)
            fmt.Println("over!")
            wg.Wait()
        }

        func say2(s string, waitGroup *sync.WaitGroup) {
            defer waitGroup.Done()

            for i := 0; i < 3; i++ {
                fmt.Println(s)
            }
        }

        輸出,注意順序混亂是因為并發(fā)執(zhí)行

        hello
        hello
        hello
        over!
        world
        world
        world

        小心缺陷

        簡短的例子,注意循環(huán)傳入的變量用中間變量替代,防止閉包 bug

        func errFunc() {
         var wg sync.WaitGroup
         sList := []string{"a""b"}
         wg.Add(len(sList))
         for _, d := range sList {
          go func() {
           defer wg.Done()
           fmt.Println(d)
          }()
         }
         wg.Wait()
        }

        輸出,可以發(fā)現全部變成了最后一個

        b
        b

        父協程與子協程是并發(fā)的。父協程上的for循環(huán)瞬間執(zhí)行完了,內部的協程使用的是d最后的值,這就是閉包問題。

        解決方法當作參數傳入

        func correctFunc() {
         var wg sync.WaitGroup
         sList := []string{"a""b"}
         wg.Add(len(sList))
         for _, d := range sList {
          go func(str string) {
           defer wg.Done()
           fmt.Println(str)
          }(d)
         }
         wg.Wait()
        }

        輸出

        b
        a

        要留意 range 中的value有可能出現 1.7.3 有可能會遇到的坑!(位于電子書golang.coding3min.com中)

        瀏覽 53
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            美女高潮动态视频 | 日韩无码高清一区二区 | 日韩操屄 | 五月天激情国产综合婷婷 | 男女尻屄 | 国产精品呦呦 | 日韩成人一区二区三区四区不卡在线 | freehdxxxxjapanmovie | 探花风韵犹存少妇在线播放 | 91精品短视频 |