<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          二分遞歸版orDone的問題

          共 3205字,需瀏覽 7分鐘

           ·

          2021-09-07 12:34

          今天在修正昨天的文章《orDone 的兩種實(shí)現(xiàn)》中的壓測(cè)代碼時(shí),無意發(fā)現(xiàn)其中的二分遞歸版的代碼是有問題的。

          主要是goroutine泄露的問題,下邊簡(jiǎn)單說明下:

          (參考自文章 記一次學(xué)習(xí) orDone 模式爬坑經(jīng)歷[1] 

          goroutine 泄露

          orDone := make(chan interface{})
          go func() {
              defer close(orDone)
              switch len(channels) {
              case 2// 2個(gè)也是一種特殊情況
                  ...
              default//超過兩個(gè),二分法遞歸處理
                  m := len(channels) / 2
                  select {
                  case <-or(channels[:m]...):
                  case <-or(channels[m:]...):
                  }
              }
          }()

          原代碼遞歸時(shí),沒有將結(jié)束通道orDone合并,在orDone關(guān)閉后,沒法通知遞歸中的協(xié)程退出,有goroutine泄露的可能。可修改為

          select {
             case <-OrWithIssue(append(channels[:m:m], orDone)...):
             case <-OrWithIssue(append(channels[m:], orDone)...):
          }

          無限遞歸

          以上代碼時(shí),還有個(gè)問題是在參數(shù)為三個(gè)chan時(shí)會(huì)無限遞歸,(文末參考文章里有通過打印協(xié)程數(shù)來測(cè)試這個(gè)問題的代碼,感興趣可以去看下)

          遞歸樹如下:

          // 3個(gè)時(shí)有無限遞歸的問題:
              f(3)
          f(2)  f(3)
              f(2)  f(3)
                 f(2)  f(3)
                          ...

          所以需要對(duì) 3 這種case區(qū)分處理

          最終代碼如下:

          func OrRecur(channels ...<-chan interface{}) <-chan interface{} {
           // 特殊情況,只有0個(gè)或者1個(gè)chan
           switch len(channels) {
           case 0:
            return nil
           case 1:
            return channels[0]
           }

           orDone := make(chan interface{})
           go func() {
            defer close(orDone)

            switch len(channels) {
            case 2// 特殊情況
             select {
             case <-channels[0]:
             case <-channels[1]:
             }
            case 3// 特殊情況
             select {
             case <-channels[0]:
             case <-channels[1]:
             case <-channels[2]:
             }
            default// 超過3個(gè),二分法遞歸處理
             m := len(channels) / 2
             select {
             case <-OrRecur(append(channels[:m:m], orDone)...):
             case <-OrRecur(append(channels[m:], orDone)...):
             }
            }
           }()

           return orDone
          }

          最后,再補(bǔ)充下修正后壓測(cè)結(jié)果,基本上,二分遞歸比反射性能更好些

          感興趣可以自己跑下壓測(cè)代碼[2]

          雖然是常見的 orDone 模式,但還是有不少可以探究的地方,想要用好 chan 還是需要足夠仔細(xì)啊。

          參考資料

          [1]

          記一次學(xué)習(xí) orDone 模式爬坑經(jīng)歷: https://tjjsjwhj.me/2021/04/25/go-or-done/

          [2]

          壓測(cè)代碼: https://github.com/NewbMiao/Dig101-Go/tree/master/concurrency/channel/schedule/orDone



          推薦閱讀


          福利

          我為大家整理了一份從入門到進(jìn)階的Go學(xué)習(xí)資料禮包,包含學(xué)習(xí)建議:入門看什么,進(jìn)階看什么。關(guān)注公眾號(hào) 「polarisxu」,回復(fù) ebook 獲取;還可以回復(fù)「進(jìn)群」,和數(shù)萬 Gopher 交流學(xué)習(xí)。

          瀏覽 32
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  69视频免费在线 | 99青草国产精品视频无码一区 | 成人网站18| www久久91 | 日韩国产av |