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

          在 Go 語言中管理 Concurrency 的三種方式

          共 1333字,需瀏覽 3分鐘

           ·

          2020-08-12 02:06

          點擊上方藍色“Go語言中文網(wǎng)”關(guān)注我們,領(lǐng)全套Go資料,每天學習?Go?語言

          相信大家踏入 Go 語言的世界,肯定是被強大的并發(fā)(Concurrency)所吸引,Go 語言用最簡單的關(guān)鍵字go就可以將任務(wù)丟到后臺處理,但是開發(fā)者怎么有效率的控制并發(fā),這是入門 Go 語言必學的技能,本章會介紹幾種方式來帶大家認識并發(fā),而這三種方式分別對應(yīng)到三個不同的名詞:WaitGroup,Channel,及 Context。下面用簡單的范例帶大家了解。

          WaitGroup

          先來了解有什么情境需要使用到 WaitGroup,假設(shè)您有兩臺機器需要同時上傳最新的代碼,兩臺機器分別上傳完成后,才能執(zhí)行最后的重啟步驟。就像是把一個工作同時拆成好幾份同時一起做,可以減少時間,但是最后需要等到全部做完,才能執(zhí)行下一步,這時候就需要用到 WaitGroup 才能做到。

          package?main

          import?(
          ????"fmt"
          ????"sync"
          )

          func?main()?{
          ????var?wg?sync.WaitGroup
          ????i?:=?0
          ????wg.Add(3)?//task?count?wait?to?do
          ????go?func()?{
          ????????defer?wg.Done()?//?finish?task1
          ????????fmt.Println("goroutine?1?done")
          ????????i++
          ????}()
          ????go?func()?{
          ????????defer?wg.Done()?//?finish?task2
          ????????fmt.Println("goroutine?2?done")
          ????????i++
          ????}()
          ????go?func()?{
          ????????defer?wg.Done()?//?finish?task3
          ????????fmt.Println("goroutine?3?done")
          ????????i++
          ????}()
          ????wg.Wait()?//?wait?for?tasks?to?be?done
          ????fmt.Println("all?goroutine?done")
          ????fmt.Println(i)
          }

          Channel

          另外一種實際的案例就是,我們需要主動通知一個 Goroutine 進行停止的動作。換句話說,當 App 啟動時,會在后臺跑一些監(jiān)控程序,而當整個 App 需要停止前,需要發(fā)個 Notification 給后臺的監(jiān)控程序,將其先停止,這時候就需要用到 Channel 來通知。看下下面這個例子:

          package?main

          import?(
          ????"fmt"
          ????"time"
          )

          func?main()?{
          ????exit?:=?make(chan?bool)
          ????go?func()?{
          ????????for?{
          ????????????select?{
          ????????????case?<-exit:
          ????????????????fmt.Println("Exit")
          ????????????????return
          ????????????case?<-time.After(2?*?time.Second):
          ????????????????fmt.Println("Monitoring")
          ????????????}
          ????????}
          ????}()
          ????time.Sleep(5?*?time.Second)
          ????fmt.Println("Notify?Exit")
          ????exit?<-?true?//keep?main?goroutine?alive
          ????time.Sleep(5?*?time.Second)
          }

          上面的例子可以發(fā)現(xiàn),用了一個 Gogourtine 和 Channel 來控制。可以想像當后臺有無數(shù)個 Goroutine 的時候,我們就需要用多個 Channel 才能進行控制,也許 Goroutine 內(nèi)又會產(chǎn)生 Goroutine,開發(fā)者這時候就會發(fā)現(xiàn)已經(jīng)無法單純使用 Channel 來控制多個 Goroutine 了。這時候解決方式會是傳遞 Context

          Context

          大家可以想像,今天有一個后臺任務(wù) A,A 任務(wù)又產(chǎn)生了 B 任務(wù),B 任務(wù)又產(chǎn)生了 C 任務(wù),也就是可以按照此模式一直產(chǎn)生下去,假設(shè)中途我們需要停止 A 任務(wù),而 A 又必須告訴 B 及 C 要一起停止,這時候通過 context 方式是最快的了。

          package?main

          import?(
          ????"context"
          ????"fmt"
          ????"time"
          )

          func?foo(ctx?context.Context,?name?string)?{
          ????go?bar(ctx,?name)?//?A?calls?B
          ????for?{
          ????????select?{
          ????????case?<-ctx.Done():
          ????????????fmt.Println(name,?"A?Exit")
          ????????????return
          ????????case?<-time.After(1?*?time.Second):
          ????????????fmt.Println(name,?"A?do?something")
          ????????}
          ????}
          }

          func?bar(ctx?context.Context,?name?string)?{
          ????for?{
          ????????select?{
          ????????case?<-ctx.Done():
          ????????????fmt.Println(name,?"B?Exit")
          ????????????return
          ????????case?<-time.After(2?*?time.Second):
          ????????????fmt.Println(name,?"B?do?something")
          ????????}
          ????}
          }

          func?main()?{
          ????ctx,?cancel?:=?context.WithCancel(context.Background())
          ????go?foo(ctx,?"FooBar")
          ????fmt.Println("client?release?connection,?need?to?notify?A,?B?exit")
          ????time.Sleep(5?*?time.Second)
          ????cancel()?//mock?client?exit,?and?pass?the?signal,?ctx.Done()?gets?the?signal??time.Sleep(3?*?time.Second)
          ????time.Sleep(3?*?time.Second)
          }

          大家可以把 context 想成是一個 controller,可以隨時控制不確定個數(shù)的 Goroutine,由上往下,只要宣告context.WithCancel后,再任意時間點都可以通過cancel()來停止整個后臺服務(wù)。實際案例會用在當 App 需要重新啟動時,要先通知全部 goroutine 停止,正常停止后,才會重新啟動 App。

          總結(jié)

          根據(jù)不同的情境跟狀況來選擇不同的方式,做一個總結(jié):

          • WaitGroup:需要將單一個工作分解成多個子任務(wù),等到全部完成后,才能進行下一步,這時候用 WaitGroup 最適合了
          • Channel + Select:Channel 只能用在比較單純的 Goroutine 情況下,如果要管理多個 Goroutine,建議還是 走 context 會比較適合
          • Context:如果您想一次控制全部的 Goroutine,相信用 context 會是最適合不過的,當然 context 不只有這特性,詳細可以參考『用 10 分鐘了解 Go 語言 context package 使用場景及介紹

          作者:AppleBOY

          原文鏈接:https://blog.wu-boy.com/2020/08/three-ways-to-manage-concurrency-in-go/



          推薦閱讀


          學習交流 Go 語言,掃碼回復「進群」即可


          站長 polarisxu

          自己的原創(chuàng)文章

          不限于 Go 技術(shù)

          職場和創(chuàng)業(yè)經(jīng)驗


          Go語言中文網(wǎng)

          每天為你

          分享 Go 知識

          Go愛好者值得關(guān)注


          瀏覽 26
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  女人超碰 | 免费av网站在线观看 | 18禁黄网站禁片免费看 | 欧美在线三级 | 很污的视频网站 |