<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>

          看似一道簡(jiǎn)單的 Go 題,考點(diǎn)不少:一道字節(jié)跳動(dòng)面試題解析

          共 332字,需瀏覽 1分鐘

           ·

          2020-11-18 06:52

          我是一只可愛(ài)的土撥鼠,專注于分享 Go 職場(chǎng)、招聘和求職,解 Gopher 之憂!歡迎關(guān)注我。

          網(wǎng)上看到有人分享去字節(jié)跳動(dòng)的面試 Go 的經(jīng)驗(yàn)[1],從面試題來(lái)看,應(yīng)該是比較初級(jí)的職位,這方面土撥鼠之前給大家分析過(guò)他家初級(jí)職位的要求。

          這份面試經(jīng)驗(yàn)總結(jié)中(其實(shí)談不上總結(jié),只是面試題的記錄,并沒(méi)有總結(jié)分析答案),有一道 Go 相關(guān)的題,也是一個(gè)老生常談的問(wèn)題:以下代碼有什么問(wèn)題,怎么解決?

          total,?sum?:=?0,?0
          for?i?:=?1;?i?<=?10;?i++?{
          ????sum?+=?i
          ????go?func()?{
          ????????total?+=?i
          ????}()
          }
          fmt.Printf("total:%d?sum?%d",?total,?sum)

          01 考點(diǎn)一

          我相信很多人應(yīng)該一眼看出了其中的一個(gè)問(wèn)題,那就是 i 使用的問(wèn)題。常見(jiàn)的題目是這樣的:以下代碼,輸出什么?

          for?i?:=?1;?i?<=?10;?i++?{
          ??go?func()?{
          ????fmt.Println(i)
          ??}()
          }
          time.Sleep(1e9)

          相信很多人知道,輸出 一堆 11,而不是期望的輸出 1 到 10。

          怎么改進(jìn)?你應(yīng)該也知曉。

          for?i?:=?1;?i?<=?10;?i++?{
          ??go?func(i?int)?{
          ????fmt.Println(i)
          ??}(i)
          }
          time.Sleep(1e9)

          (當(dāng)然這里的輸出順序是亂的,大家應(yīng)該清楚)

          02 考點(diǎn)二

          該題的第二個(gè)考點(diǎn):data race。因?yàn)榇嬖诙?goroutine 同時(shí)寫(xiě) total 變量的問(wèn)題,所以有數(shù)據(jù)競(jìng)爭(zhēng)。可以加上 -race 參數(shù)驗(yàn)證:

          $?go?run?-race?main.go
          ==================
          WARNING:?DATA?RACE
          Read?at?0x00c0001b4020?by?goroutine?8:
          ??main.main.func1()
          ??????/Users/xuxinhua/main.go:12?+0x57

          Previous?write?at?0x00c0001b4020?by?main?goroutine:
          ??main.main()
          ??????/Users/xuxinhua/main.go:9?+0x10b

          Goroutine?8?(running)?created?at:
          ??main.main()
          ??????/Users/xuxinhua/main.go:11?+0xe7
          ==================

          這可以通過(guò)加鎖的方式解決:

          var?mutex?sync.Mutex
          total,?sum?:=?0,?0
          for?i?:=?1;?i?<=?10;?i++?{
          ??sum?+=?i
          ??go?func(i?int)?{
          ????mutex.Lock()
          ????total?+=?i
          ????mutex.Unlock()
          ??}(i)
          }

          此外,也可以通過(guò) atomic 包解決:(注意 total 的類型,因?yàn)?atomic.AddInt64 需要)

          var?total?int64
          sum?:=?0
          for?i?:=?1;?i?<=?10;?i++?{
          ??sum?+=?i
          ??go?func(i?int)?{
          ????atomic.AddInt64(&total,?int64(i))
          ??}(i)
          }

          通過(guò) -race 你驗(yàn)證,發(fā)現(xiàn) data race 沒(méi)了。

          細(xì)心的你不知道發(fā)現(xiàn)沒(méi)有,以上代碼我故意把最后的 fmt 輸出那一行去掉了,因?yàn)樗昧?total 變量,避免它導(dǎo)致 data race。這引出考點(diǎn)三。

          03 考點(diǎn)三

          我上面都沒(méi)有給完整的代碼,因?yàn)榻?jīng)過(guò)上面兩步,最終的結(jié)果還是不對(duì)的。從上面說(shuō)的 fmt 輸出代碼去掉就說(shuō)明還有問(wèn)題。

          初學(xué) Go 應(yīng)該遇到類似這樣的問(wèn)題,下面代碼一般沒(méi)有輸出。

          package?main

          import?"fmt"

          func?main()?{
          ?go?func()?{
          ??fmt.Println("Hello?World!")
          ?}()
          }

          原因是 main 函數(shù)先退出了,開(kāi)啟的 goroutine 根本沒(méi)有機(jī)會(huì)執(zhí)行。所以,常見(jiàn)的解決辦法是在最后加一個(gè) Sleep:

          package?main

          import?"fmt"

          func?main()?{
          ?go?func()?{
          ??fmt.Println("Hello?World!")
          ?}()
          ??
          ??time.Sleep(1e9)
          }

          Sleep 會(huì)讓 main goroutine 休眠,調(diào)度器調(diào)度其他 goroutine 運(yùn)行。

          回到開(kāi)頭的題目其實(shí)也存在這個(gè)問(wèn)題,通過(guò)在 fmt 語(yǔ)句之前加上 Sleep,基本能得到正確的結(jié)果:

          var?total?int64
          sum?:=?0
          for?i?:=?1;?i?<=?10;?i++?{
          ????sum?+=?i
          ????go?func(i?int)?{
          ????????atomic.AddInt64(&total,?int64(i))
          ????}(i)
          }
          time.Sleep(1e9)

          fmt.Printf("total:%d?sum?%d",?total,?sum)

          但如果加上 -race 發(fā)現(xiàn)還是有問(wèn)題:

          $?go?run?-race?main.go
          ==================
          WARNING:?DATA?RACE
          Read?at?0x00c00001c0b0?by?main?goroutine:
          ??main.main()
          ??????/Users/xuxinhua/main.go:20?+0xe4

          Previous?write?at?0x00c00001c0b0?by?goroutine?7:
          ??sync/atomic.AddInt64()
          ??????/Users/xuxinhua/.go/current/src/runtime/race_amd64.s:276?+0xb
          ??main.main.func1()
          ??????/Users/xuxinhua/main.go:15?+0x44

          Goroutine?7?(finished)?created?at:
          ??main.main()
          ??????/Users/xuxinhua/main.go:14?+0xa4
          ==================
          total:55?sum?55Found?1?data?race(s)

          所以,這種方式是不靠譜的,這時(shí)正確的方式是使用 sync.WaitGroup。

          package?main

          import?(
          ????"sync/atomic"
          ????"sync"
          ????"fmt"
          )

          func?main()?{
          ????var?wg?sync.WaitGroup
          ????var?total?int64
          ????sum?:=?0
          ????for?i?:=?1;?i?<=?10;?i++?{
          ????????wg.Add(1)
          ????????sum?+=?i
          ????????go?func(i?int)?{
          ????????????defer?wg.Done()
          ????????????atomic.AddInt64(&total,?int64(i))
          ????????}(i)
          ????}
          ????wg.Wait()

          ????fmt.Printf("total:%d?sum?%d",?total,?sum)
          }

          04 總結(jié)

          通過(guò)上面的分析,發(fā)現(xiàn)看起來(lái)是一個(gè)簡(jiǎn)單的題目,其實(shí)考點(diǎn)好幾個(gè)。這個(gè)題目還是挺好的,字節(jié)跳動(dòng)面試官出的這道題還是有點(diǎn)水平。你覺(jué)得呢?

          參考資料

          [1]

          面試 Go 的經(jīng)驗(yàn): https://zhuanlan.zhihu.com/p/132813717




          推薦閱讀


          歡迎搜索或掃碼關(guān)注我!


          瀏覽 39
          點(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>
                  粉嫩小泬BBBB免费看-百度 | 国产AV高清 | 91九色91蝌蚪91窝成人 | 久操久热 | 亚洲精品宾馆在线 |