欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語(yǔ)言并發(fā)之WaitGroup的用法詳解

 更新時(shí)間:2023年06月09日 09:17:27   作者:zsx_yiyiyi  
這篇文章主要詳細(xì)介紹了Go語(yǔ)言并發(fā)中得到WaitGroup,文中有相關(guān)的代碼示例供大家參考,對(duì)我們的學(xué)習(xí)或工作有一定的參考價(jià)值,感興趣的同學(xué)跟著小編一起來(lái)學(xué)習(xí)吧

1、Go語(yǔ)言并發(fā)之WaitGroup

goroutine 和 chan,一個(gè)用于并發(fā),另一個(gè)用于通信。沒(méi)有緩沖的通道具有同步的功能,除此之外,sync 包也提

供了多個(gè) goroutine 同步的機(jī)制,主要是通過(guò) WaitGroup 實(shí)現(xiàn)的。

WaitGroup 用來(lái)等待多個(gè) goroutine 完成,main goroutine 調(diào)用 Add 設(shè)置需要等待 goroutine 的數(shù)目,每一個(gè)

goroutine 結(jié)束時(shí)調(diào)用 Done(),Wait() 被 main 用來(lái)等待所有的 goroutine 完成。

主要數(shù)據(jù)結(jié)構(gòu)和操作如下:

type WaitGroup struct {
	// contains filtered or unexported fields
}
// 添加等待信號(hào)
func (wg*WaitGroup) Add (delta int)
// 釋放等待信號(hào)
func (wg*WaitGroup) Done()
// 等待
func (wg*WaitGroup) Wait()

下面的程序演示如何使用 sync.WaitGroup 完成多個(gè) goroutine 之間的協(xié)同工作。

package main
import (
	"net/http"
	"sync"
)
var wg sync.WaitGroup
var urls = []string{
	"https://news.sina.com.cn/",
	"https://www.bilibili.com/",
	"https://www.qq.com/",
}
func main() {
	for _, url := range urls {
		//每一個(gè)url啟動(dòng)一個(gè)goroutine,同時(shí)給wg加1
		wg.Add(1)
		// 啟動(dòng)一個(gè)goroutine獲取URL
		go func(url string) {
			// 當(dāng)前goroutine結(jié)束后給wg計(jì)數(shù)減1 ,wg.Done()等價(jià)于wg.Add(-1)
			// defer wg.Add(-1)
			defer wg.Done()
			// 發(fā)送http get請(qǐng)求并打印http返回碼
			resp, err := http.Get(url)
			if err == nil {
				println(resp.Status)
			}
		}(url)
	}
	// 等待所有HTTP獲取完成
	wg.Wait()
}

# 輸出
501 Not Implemented
200 OK
200 OK

1.1 不加鎖

多線(xiàn)程中使用睡眠函數(shù)不優(yōu)雅,直接用 sync.WaitGroup 保證一個(gè) goroutine 剛退出就可以繼續(xù)執(zhí)行,不需要自

己猜需要 sleep 多久。

package main
import (
	"fmt"
	"sync"
)
var wg sync.WaitGroup
func main() {
	// 啟動(dòng)一個(gè)goroutine就登記+1,啟動(dòng)十個(gè)就+10
	wg.Add(10)
	var count = 0
	for i := 0; i < 10; i++ {
		go func() {
			// goroutine結(jié)束就登記-1
			defer wg.Done()
			for j := 0; j < 100000; j++ {
				count++
			}
		}()
	}
	// 等待所有登記的goroutine都結(jié)束
	wg.Wait()
	// 346730
	fmt.Print(count)
}

啟動(dòng)十個(gè)goroutine對(duì)count自增10w次,理想狀況為100w,但由于沒(méi)有鎖,會(huì)出現(xiàn)實(shí)際情況遠(yuǎn)遠(yuǎn)小于并且不相等

的情況。為什么會(huì)出現(xiàn)這樣的結(jié)果?因?yàn)樽栽霾⒉皇且粋€(gè)原子操作,很可能幾個(gè)goroutine同時(shí)讀到同一個(gè)數(shù),自

增,又將同樣的數(shù)寫(xiě)了回去。

1.2 互斥鎖

1.2.1 直接使用鎖

共享資源是count變量,臨界區(qū)是count++,臨界區(qū)之前加鎖,使其他goroutine在臨界區(qū)阻塞,離開(kāi)臨界區(qū)解

鎖,就可以解決這個(gè) data race 的問(wèn)題。go語(yǔ)言是通過(guò) sync.Mutex 實(shí)現(xiàn)這一功能。

package main
import (
	"fmt"
	"sync"
)
var wg sync.WaitGroup
func main() {
	// 定義鎖
	var mu sync.Mutex
	wg.Add(10)
	var count = 0
	for i := 0; i < 10; i++ {
		go func() {
			defer wg.Done()
			for j := 0; j < 100000; j++ {
				// 加鎖
				mu.Lock()
				count++
				// 解鎖
				mu.Unlock()
			}
		}()
	}
	wg.Wait()
	// 1000000
	fmt.Print(count)
}

1.2.2 嵌入字段方式使用鎖

把 Mutex 嵌入 struct,可以直接在這個(gè) struct 上使用 Lock/Unlock。

package main
import (
	"fmt"
	"sync"
)
var wg sync.WaitGroup
type Counter struct {
	sync.Mutex
	Count uint64
}
func main() {
	var counter Counter
	wg.Add(10)
	for i := 0; i < 10; i++ {
		go func() {
			defer wg.Done()
			for j := 0; j < 100000; j++ {
				counter.Lock()
				counter.Count++
				counter.Unlock()
			}
		}()
	}
	wg.Wait()
	// 1000000
	fmt.Print(counter.Count)
}

1.2.3 把加/解鎖封裝成方法

package main
import (
	"fmt"
	"sync"
)
var wg sync.WaitGroup
type Counter struct {
	mu    sync.Mutex
	count uint64
}
func (c *Counter) Incr() {
	c.mu.Lock()
	c.count++
	c.mu.Unlock()
}
func (c *Counter) Count() uint64 {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.count
}
func main() {
	var counter Counter
	// 啟動(dòng)一個(gè)goroutine就登記+1,啟動(dòng)十個(gè)就+10
	wg.Add(10)
	for i := 0; i < 10; i++ {
		go func() {
			// goroutine結(jié)束就登記-1
			defer wg.Done()
			for j := 0; j < 100000; j++ {
				counter.Incr()
			}
		}()
	}
	// 等待所有登記的goroutine都結(jié)束
	wg.Wait()
	// 1000000
	fmt.Print(counter.Count())
}

到此這篇關(guān)于Go語(yǔ)言并發(fā)之WaitGroup的用法詳解的文章就介紹到這了,更多相關(guān)Go語(yǔ)言 WaitGroup內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • golang給函數(shù)參數(shù)設(shè)置默認(rèn)值的幾種方式小結(jié)(函數(shù)參數(shù)默認(rèn)值

    golang給函數(shù)參數(shù)設(shè)置默認(rèn)值的幾種方式小結(jié)(函數(shù)參數(shù)默認(rèn)值

    在日常開(kāi)發(fā)中我們有時(shí)候需要使用默認(rèn)設(shè)置,下面這篇文章主要給大家介紹了關(guān)于golang給函數(shù)參數(shù)設(shè)置默認(rèn)值的幾種方式小結(jié)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-01-01
  • goFrame的gqueue與channe的區(qū)別

    goFrame的gqueue與channe的區(qū)別

    這篇文章主要介紹了goFrame的gqueue與channe的區(qū)別,channel的作用是用于go協(xié)程間的通信,goroutine和channel是支持高并發(fā)的重要組成部分,更多兩者詳細(xì)介紹需要的小伙伴可以參考下面文章內(nèi)容
    2022-06-06
  • Go 字符串格式化的實(shí)例代碼詳解

    Go 字符串格式化的實(shí)例代碼詳解

    這篇文章主要介紹了Go 字符串格式化的實(shí)例代碼詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 淺談golang slice 切片原理

    淺談golang slice 切片原理

    這篇文章主要介紹了淺談golang slice 切片原理,詳細(xì)的介紹了golang slice 切片的概念和原理,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-11-11
  • Go?GORM?事務(wù)詳細(xì)介紹

    Go?GORM?事務(wù)詳細(xì)介紹

    這篇文章主要介紹了Go?GORM事務(wù)詳細(xì)介紹,GORM?會(huì)在事務(wù)里執(zhí)行寫(xiě)入操作創(chuàng)建、更新、刪除,具體詳細(xì)介紹需要的朋友可以參考下面文章的簡(jiǎn)單介紹
    2022-07-07
  • 基于Go語(yǔ)言實(shí)現(xiàn)類(lèi)似tree命令的小程序

    基于Go語(yǔ)言實(shí)現(xiàn)類(lèi)似tree命令的小程序

    tree?命令是一個(gè)小型的跨平臺(tái)命令行程序,用于遞歸地以樹(shù)狀格式列出或顯示目錄的內(nèi)容。本文將通過(guò)Go語(yǔ)言實(shí)現(xiàn)類(lèi)似tree命令的小程序,需要的可以參考一下
    2022-10-10
  • 阿里云go開(kāi)發(fā)環(huán)境搭建過(guò)程

    阿里云go開(kāi)發(fā)環(huán)境搭建過(guò)程

    這篇文章主要介紹了阿里云go開(kāi)發(fā)環(huán)境搭建過(guò)程,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • 一文帶你全面掌握Go語(yǔ)言中的正則表達(dá)式

    一文帶你全面掌握Go語(yǔ)言中的正則表達(dá)式

    正則表達(dá)式是一種強(qiáng)大的模式匹配工具,能夠在文本中進(jìn)行靈活的搜索和替換操作,本文將介紹?Golang?中的正則表達(dá)式語(yǔ)法,包括常用的匹配符號(hào)、模式修飾符以及示例應(yīng)用,希望對(duì)大家有所幫助
    2023-05-05
  • mac下安裝golang框架iris的方法

    mac下安裝golang框架iris的方法

    這篇文章主要介紹了mac下安裝golang框架iris的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • golang 通用Contains方法分享

    golang 通用Contains方法分享

    這篇文章主要介紹了golang 通用Contains方法分享,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04

最新評(píng)論