最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解決Golang 中使用WaitGroup的那點(diǎn)坑

 更新時(shí)間:2021年04月27日 10:16:38   作者:he_silong  
這篇文章主要介紹了解決Golang 中使用WaitGroup的那點(diǎn)坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧

sync.WaitGroup對(duì)于Golang開發(fā)者來說并不陌生,其經(jīng)常作為多協(xié)程之間同步的一種機(jī)制。用好它勢(shì)必會(huì)讓你事半功倍,但是一旦錯(cuò)用將引發(fā)問題。

關(guān)于WaitGroup的使用網(wǎng)上有很多例子,在此就不做介紹了,我想說的是我在項(xiàng)目中使用WaitGroup遇到的坑。

在項(xiàng)目中,因?yàn)榉?wù)器有同步需求, 所以直接使用了WaitGroup,但是未考慮使用場(chǎng)景,結(jié)果在項(xiàng)目上線之后,高峰期的時(shí)候客戶端經(jīng)常出現(xiàn)卡頓,經(jīng)過多方查找,才發(fā)現(xiàn)如果使用WaitGroup的時(shí)候,未啟動(dòng)單獨(dú)的goroutine,那么極有可能造成主線程的阻塞

所以我做了下面的測(cè)試(測(cè)試中,我把WaitGroup置于協(xié)程內(nèi)):

import (
 "fmt"
 "sync"
 "time"
)
 
func main() {
    fmt.Println("main-1")
 testW()
 fmt.Println("main-2")
 time.Sleep(time.Duration(15) * time.Second) 
}
 
func testW() {
 fmt.Println("testW-1")
 go func() {
  var wg sync.WaitGroup
  fmt.Println("testW-2")
  testW1(&wg)
  fmt.Println("testW-5")
  wg.Wait()
  fmt.Println("testW-6")
 }()
}
 
func testW1(wg *sync.WaitGroup) {
 wg.Add(1)
 fmt.Println("testW-3")
 time.AfterFunc(time.Second*5, func() {
  wg.Done()
 })
 fmt.Println("testW-4")
 
}

輸出為:

main-1

testchan-1

main-2

testchan-2

testchan-3

testchan-4

testchan-5

// 過5秒

testchan-6

總結(jié):

將WaitGroup用于goroutine內(nèi),不會(huì)導(dǎo)致主線程的阻塞,同樣可以實(shí)現(xiàn)同步的效果。

補(bǔ)充:WaitGroup的簡(jiǎn)單用法(等待組)

你品一下人家這名字,等待組。等待什么,等待goroutine完成啊。有些時(shí)候,我們啟動(dòng)多個(gè)goroutine去執(zhí)行任務(wù),我舉個(gè)例子

listip := []string{"10.0.9.11","10.0.9.22","10.0.9.33"}
for _, ip := range(listip) {
    //假設(shè)我們執(zhí)行一個(gè)ping ip 的邏輯
    go PingIPWork(ip)
}

我這里執(zhí)行了一個(gè)多ip去ping的邏輯,一般這種時(shí)候,你要是執(zhí)行一波,人家肯定毛都不會(huì)返回給你,為什么?因?yàn)槿思抑骶€程直接就退出了,還是那句話,你又沒告訴人家主線程要等這ip全部都ping 完,所以你必須要加個(gè)等待,等著Goroutine完成,這里我再舉一個(gè)網(wǎng)上的例子

package main
import (
    "fmt"
)
func main() {
    go func() {
        fmt.Println("Goroutine 1")
    }()
    go func() {
        fmt.Println("Goroutine 2")
    }()
    //來個(gè)睡眠,等Goroutine結(jié)束
    time.Sleep(time.Second * 1)
}

看到了么,加了一個(gè)sleep,用sleep去等著Goroutine跑完,上面我舉的那個(gè)例子也可以這么來

listip := []string{"10.0.9.11","10.0.9.22","10.0.9.33"}
for _, ip := range(listip) {
    //假設(shè)我們執(zhí)行一個(gè)ping ip 的邏輯
    go PingIPWork(ip)
}
time.Sleep(time.Second * 1)

加個(gè)sleep可以等待完成,但是萬一啊,Goroutine有的跑的快,有的慢,你那sleep就一秒,要是有的Goroutine沒跑完不就白瞎了嗎,所以咱們需要一個(gè)機(jī)制,這個(gè)機(jī)制可以幫助咱們?nèi)ス芾鞧oroutine,讓我們知道Goroutine這東西什么時(shí)候停,什么時(shí)候完成。

所以,WaitGroup這個(gè)東西,就可以幫助我們解決這個(gè)問題,還是老樣子,我舉一個(gè)簡(jiǎn)單的例子來說明我的想法。

package main
import (
    "fmt"
 "sync"
)
func PingIPWork(ip string) {
 fmt.Println(ip)
}
func main() {
    //定義一個(gè)等待阿祖
 var wg sync.WaitGroup
 wg.Add(3) // 因?yàn)橛?個(gè)Ip,咱們定義三個(gè)動(dòng)作,所以來三個(gè)計(jì)數(shù)
 listip := []string{"10.0.9.11","10.0.9.22","10.0.9.33"}
 for _, ip := range(listip) {
  //假設(shè)我們執(zhí)行一個(gè)ping ip 的邏輯
  go func(ip string) {
            //執(zhí)行一個(gè)work
            PingIPWork(ip)
            //操作完成之后,done一個(gè)計(jì)數(shù),也就是3-1
   wg.Done()
  }(ip)
 }
    //等待
 wg.Wait() // 等待,直到計(jì)數(shù)為0
}

這里我舉了一個(gè)簡(jiǎn)單的例子,其實(shí)wg的用法較為簡(jiǎn)單,在這個(gè)例子里面我們用到了

wg.wait
等待Goroutine結(jié)束之后退出主進(jìn)程
wg.Add
添加Goroutine,其實(shí)你可以把它想成,可添加的最大Goroutine數(shù)
wg.Done
想象成銷毀參數(shù),當(dāng)Goroutine結(jié)束之后調(diào)用,意思就是,你沒了,我減1

WaitGroup的其他注意事項(xiàng)

將Wg作為參數(shù)進(jìn)行傳遞的時(shí)候,需要使用指針

有些時(shí)候,咱們不想寫的這么麻煩,就尋思怎么才能簡(jiǎn)單一點(diǎn),或者可變性稍微強(qiáng)一點(diǎn),有些時(shí)候我們要把wg最為參數(shù),在函數(shù)內(nèi)部調(diào)用,我們?cè)撛趺磳懩兀?/p>

package main
import (
 "fmt"
 "sync"
)
func PingIPWork(ip string, wg *sync.WaitGroup) {
 fmt.Println(ip)
 wg.Done()
}
func main() {
 var wg sync.WaitGroup
 wg.Add(3) // 因?yàn)橛袃蓚€(gè)動(dòng)作,所以增加2個(gè)計(jì)數(shù)
 listip := []string{"10.0.9.11","10.0.9.22","10.0.9.33"}
 for _, ip := range(listip) {
  //假設(shè)我們執(zhí)行一個(gè)ping ip 的邏輯
  go PingIPWork(ip, &wg)
  }
 wg.Wait() // 等待,直到計(jì)數(shù)為0
}

看到了么,如果你把Wg作為參數(shù)進(jìn)行傳遞,你得要用指針的形式傳值,否則就會(huì)死鎖!?。。。。。?!

Wg.Add的數(shù)值不能為負(fù)

wg.Add()的數(shù)值必須為正數(shù),如果為負(fù)數(shù),將會(huì)拋出異常。

panic: sync: negative WaitGroup counter
goroutine 1 [running]:
sync.(*WaitGroup).Add(0xc042008230, 0xffffffffffffff9c)
    D:/Go/src/sync/waitgroup.go:75 +0x1d0
main.main()
    D:/code/go/src/test-src/2-Package/sync/waitgroup/main.go:10 +0x54

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。

相關(guān)文章

  • Go 語言下基于Redis分布式鎖的實(shí)現(xiàn)方式

    Go 語言下基于Redis分布式鎖的實(shí)現(xiàn)方式

    本篇文章將詳細(xì)介紹如何正確地實(shí)現(xiàn)Redis分布式鎖,下面通過一個(gè)項(xiàng)目基于 Redis 的分布式鎖能夠提供哪些分布鎖特性,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2021-06-06
  • Golang執(zhí)行g(shù)o get私有庫(kù)提示

    Golang執(zhí)行g(shù)o get私有庫(kù)提示"410 Gone" 的問題及解決辦法

    這篇文章主要介紹了Golang執(zhí)行g(shù)o get私有庫(kù)提示”410 Gone“ 解決辦法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • golang實(shí)現(xiàn)各種情況的get請(qǐng)求操作

    golang實(shí)現(xiàn)各種情況的get請(qǐng)求操作

    這篇文章主要介紹了golang實(shí)現(xiàn)各種情況的get請(qǐng)求操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go使用select切換協(xié)程入門詳解

    Go使用select切換協(xié)程入門詳解

    這篇文章主要為大家介紹了Go使用select切換協(xié)程入門詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • go語言實(shí)現(xiàn)簡(jiǎn)單的并發(fā)網(wǎng)頁(yè)爬蟲示例

    go語言實(shí)現(xiàn)簡(jiǎn)單的并發(fā)網(wǎng)頁(yè)爬蟲示例

    在這個(gè)章節(jié)中,我們將會(huì)結(jié)合之前的知識(shí)點(diǎn),實(shí)現(xiàn)一個(gè)簡(jiǎn)易的并發(fā)網(wǎng)頁(yè)爬蟲,我們的爬蟲會(huì)先爬取一個(gè)起始頁(yè)面,提取出所有的鏈接,然后并發(fā)地爬取這些鏈接,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2023-08-08
  • Golang?strings包常用字符串操作函數(shù)

    Golang?strings包常用字符串操作函數(shù)

    Golang?中的字符串統(tǒng)一使用?UTF-8?(屬于Unicode編碼的一種實(shí)現(xiàn)方式)進(jìn)行編碼,本篇文章將結(jié)合具體實(shí)例對(duì)常用的字符串操作函數(shù)進(jìn)行介紹,感興趣的可以了解一下
    2021-12-12
  • Golang教程之不可重入函數(shù)的實(shí)現(xiàn)方法

    Golang教程之不可重入函數(shù)的實(shí)現(xiàn)方法

    這篇文章主要給大家介紹了關(guān)于Golang教程之不可重入函數(shù)的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • Go語言中切片使用的注意事項(xiàng)小結(jié)

    Go語言中切片使用的注意事項(xiàng)小結(jié)

    切片是引用類型,相信對(duì)大家來說都不陌生,下面這篇文章主要給大家總結(jié)介紹了關(guān)于Go語言中切片使用的一些注意事項(xiàng),文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-01-01
  • 深入解析Go語言編程中slice切片結(jié)構(gòu)

    深入解析Go語言編程中slice切片結(jié)構(gòu)

    這篇文章主要介紹了Go語言編程中slice切片結(jié)構(gòu),其中Append方法的用法介紹較為詳細(xì),需要的朋友可以參考下
    2015-10-10
  • Golang的第一個(gè)程序-Hello?World

    Golang的第一個(gè)程序-Hello?World

    這篇文章主要介紹了第一個(gè)Go程序-Hello?World,在編寫第一個(gè)go程序之前,我們要將系統(tǒng)的環(huán)境變量配好,下面來看具體的編一過程吧,需要的小伙伴可以參考一下
    2022-01-01

最新評(píng)論

南华县| 平阴县| 丹棱县| 平和县| 翁牛特旗| 陇南市| 福清市| 涟源市| 贞丰县| 旅游| 呼伦贝尔市| 巴青县| 巴塘县| 天柱县| 蒙阴县| 桦川县| 梨树县| 临漳县| 阿拉善左旗| 海安县| 张北县| 绵竹市| 屯留县| 北海市| 博野县| 梁山县| 沾益县| 镇江市| 连平县| 绥江县| 安新县| 惠安县| 宾阳县| 九龙县| 乌拉特前旗| 轮台县| 北京市| 榕江县| 剑河县| 吉木萨尔县| 甘肃省|