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

Golang中常見的三種并發(fā)控制方式使用小結(jié)

 更新時(shí)間:2024年01月28日 08:32:06   作者:落雷  
這篇文章主要為大家詳細(xì)介紹了如何對(duì)goroutine并發(fā)行為的控制,在Go中最常見的有三種方式:sync.WaitGroup、channel和Context,下面我們就來(lái)看看他們的具體使用吧

Go語(yǔ)言中的goroutine是一種輕量級(jí)的線程,其優(yōu)點(diǎn)在于占用資源少、切換成本低,能夠高效地實(shí)現(xiàn)并發(fā)操作。但如何對(duì)這些并發(fā)的goroutine進(jìn)行控制呢?

一提到并發(fā)控制,大家最先想到到的是鎖。Go中同樣提供了鎖的相關(guān)機(jī)制,包括互斥鎖sync.Mutex和讀寫鎖sync.RWMutex;除此之外Go還提供了原子操作sync/atomic。但這些操作都是針對(duì)并發(fā)過(guò)程中的數(shù)據(jù)安全的,并不是針對(duì)goroutine本身的。

本文主要介紹的是對(duì)goroutine并發(fā)行為的控制。在Go中最常見的有三種方式:sync.WaitGroup、channelContext

1. sync.WaitGroup

sync.WaitGroup是Go語(yǔ)言中一個(gè)非常有用的同步原語(yǔ),它可以幫助我們等待一組goroutine全部完成。在以下場(chǎng)景中,我們通常會(huì)使用sync.WaitGroup:

  • 當(dāng)我們需要在主函數(shù)中等待一組goroutine全部完成后再退出程序時(shí)。
  • 當(dāng)我們需要在一個(gè)函數(shù)中啟動(dòng)多個(gè)goroutine,并確保它們?nèi)客瓿珊笤俜祷亟Y(jié)果時(shí)。
  • 當(dāng)我們需要在一個(gè)函數(shù)中啟動(dòng)多個(gè)goroutine,并確保它們?nèi)客瓿珊笤賵?zhí)行某個(gè)操作時(shí)。
  • 當(dāng)我們需要在一個(gè)函數(shù)中啟動(dòng)多個(gè)goroutine,并確保它們?nèi)客瓿珊笤訇P(guān)閉某個(gè)資源時(shí)。
  • 當(dāng)我們需要在一個(gè)函數(shù)中啟動(dòng)多個(gè)goroutine,并確保它們?nèi)客瓿珊笤偻顺鲅h(huán)時(shí)。

在使用sync.WaitGroup時(shí),我們需要先創(chuàng)建一個(gè)sync.WaitGroup對(duì)象,然后使用它的Add方法來(lái)指定需要等待的goroutine數(shù)量。接著,我們可以使用go關(guān)鍵字來(lái)啟動(dòng)多個(gè)goroutine,并在每個(gè)goroutine中使用sync.WaitGroup對(duì)象的Done方法來(lái)表示該goroutine已經(jīng)完成。最后,我們可以使用sync.WaitGroup對(duì)象的Wait方法來(lái)等待所有的goroutine全部完成。

下面是一個(gè)簡(jiǎn)單的示例,會(huì)啟動(dòng)3個(gè)goroutine,分別休眠0s、1s和2s,主函數(shù)會(huì)在這3個(gè)goroutine結(jié)束后退出:

package main
 
import (
	"fmt"
	"sync"
	"time"
)
 
func main() {
	var wg sync.WaitGroup
 
	for i := 0; i < 3; i++ {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()
			fmt.Printf("sub goroutine sleep: %ds\n", i)
			time.Sleep(time.Duration(i) * time.Second)
		}(i)
	}
 
	wg.Wait()
	fmt.Println("main func done")
}

2. channel

在Go語(yǔ)言中,使用channel可以幫助我們更好地控制goroutine的并發(fā)。以下是一些常見的使用channel來(lái)控制goroutine并發(fā)的方法:

2.1 使用無(wú)緩沖channel進(jìn)行同步

我們可以使用一個(gè)無(wú)緩沖的channel來(lái)實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模式,其中一個(gè)goroutine負(fù)責(zé)生產(chǎn)數(shù)據(jù),另一個(gè)goroutine負(fù)責(zé)消費(fèi)數(shù)據(jù)。當(dāng)生產(chǎn)者goroutine將數(shù)據(jù)發(fā)送到channel時(shí),消費(fèi)者goroutine會(huì)阻塞等待數(shù)據(jù)的到來(lái)。這樣,我們可以確保生產(chǎn)者和消費(fèi)者之間的數(shù)據(jù)同步。

下面是一個(gè)簡(jiǎn)單的示例代碼:

package main
 
import (
    "fmt"
    "sync"
    "time"
)
 
func producer(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 10; i++ {
        ch <- i
        fmt.Println("produced", i)
        time.Sleep(100 * time.Millisecond)
    }
    close(ch)
}
 
func consumer(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := range ch {
        fmt.Println("consumed", i)
        time.Sleep(150 * time.Millisecond)
    }
}
 
func main() {
    var wg sync.WaitGroup
    ch := make(chan int)
 
    wg.Add(2)
    go producer(ch, &wg)
    go consumer(ch, &wg)
 
    wg.Wait()
}

在這個(gè)示例中,我們創(chuàng)建了一個(gè)無(wú)緩沖的channel,用于在生產(chǎn)者goroutine和消費(fèi)者goroutine之間傳遞數(shù)據(jù)。生產(chǎn)者goroutine將數(shù)據(jù)發(fā)送到channel中,消費(fèi)者goroutine從channel中接收數(shù)據(jù)。在生產(chǎn)者goroutine中,我們使用time.Sleep函數(shù)來(lái)模擬生產(chǎn)數(shù)據(jù)的時(shí)間,在消費(fèi)者goroutine中,我們使用time.Sleep函數(shù)來(lái)模擬消費(fèi)數(shù)據(jù)的時(shí)間。最后,我們使用sync.WaitGroup來(lái)等待所有的goroutine全部完成。

2.2 使用有緩沖channel進(jìn)行限流

我們可以使用一個(gè)有緩沖的channel來(lái)限制并發(fā)goroutine的數(shù)量。在這種情況下,我們可以將channel的容量設(shè)置為我們希望的最大并發(fā)goroutine數(shù)量。然后,在啟動(dòng)每個(gè)goroutine之前,我們將一個(gè)值發(fā)送到channel中。在goroutine完成后,我們從channel中接收一個(gè)值。這樣,我們可以保證同時(shí)運(yùn)行的goroutine數(shù)量不超過(guò)我們指定的最大并發(fā)數(shù)量。

下面是一個(gè)簡(jiǎn)單的示例代碼:

package main
 
import (
    "fmt"
    "sync"
)
 
func main() {
    var wg sync.WaitGroup
    maxConcurrency := 3
    semaphore := make(chan struct{}, maxConcurrency)
 
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            semaphore <- struct{}{}
            fmt.Println("goroutine", i, "started")
            // do some work
            fmt.Println("goroutine", i, "finished")
            <-semaphore
        }()
    }
 
    wg.Wait()
}

在這個(gè)示例中,我們創(chuàng)建了一個(gè)帶緩沖的channel,緩沖區(qū)大小為3。然后,我們啟動(dòng)了10個(gè)goroutine,在每個(gè)goroutine中,我們將一個(gè)空結(jié)構(gòu)體發(fā)送到channel中,表示該goroutine已經(jīng)開始執(zhí)行。在goroutine完成后,我們從channel中接收一個(gè)空結(jié)構(gòu)體,表示該goroutine已經(jīng)完成執(zhí)行。這樣,我們可以保證同時(shí)運(yùn)行的goroutine數(shù)量不超過(guò)3。

3. Context

在Go語(yǔ)言中,使用Context可以幫助我們更好地控制goroutine的并發(fā)。以下是一些常見的使用Context來(lái)控制goroutine并發(fā)的方法:

3.1 超時(shí)控制

在某些情況下,我們需要對(duì)goroutine的執(zhí)行時(shí)間進(jìn)行限制,以避免程序長(zhǎng)時(shí)間阻塞或者出現(xiàn)死鎖等問(wèn)題。使用Context可以幫助我們更好地控制goroutine的執(zhí)行時(shí)間。我們可以創(chuàng)建一個(gè)帶有超時(shí)時(shí)間的Context,然后將其傳遞給goroutine。如果goroutine在超時(shí)時(shí)間內(nèi)沒有完成執(zhí)行,我們可以使用Context的Done方法來(lái)取消goroutine的執(zhí)行。

下面是一個(gè)簡(jiǎn)單的示例代碼:

package main
 
import (
    "context"
    "fmt"
    "time"
)
 
func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()
 
    go func() {
        for {
            select {
            case <-ctx.Done():
                fmt.Println("goroutine finished")
                return
            default:
                fmt.Println("goroutine running")
                time.Sleep(500 * time.Millisecond)
            }
        }
    }()
 
    time.Sleep(3 * time.Second)
}

在這個(gè)示例中,我們創(chuàng)建了一個(gè)帶有超時(shí)時(shí)間的Context,然后將其傳遞給goroutine。在goroutine中,我們使用select語(yǔ)句來(lái)監(jiān)聽Context的Done方法,如果Context超時(shí),我們將會(huì)取消goroutine的執(zhí)行。

3.2 取消操作

在某些情況下,我們需要在程序運(yùn)行過(guò)程中取消某些goroutine的執(zhí)行。使用Context可以幫助我們更好地控制goroutine的取消操作。我們可以創(chuàng)建一個(gè)帶有取消功能的Context,然后將其傳遞給goroutine。如果需要取消goroutine的執(zhí)行,我們可以使用Context的Cancel方法來(lái)取消goroutine的執(zhí)行。

下面是一個(gè)簡(jiǎn)單的示例代碼:

package main
 
import (
    "context"
    "fmt"
    "sync"
    "time"
)
 
func main() {
    ctx, cancel := context.WithCancel(context.Background())
 
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer wg.Done()
        for {
            select {
            case <-ctx.Done():
                fmt.Println("goroutine finished")
                return
            default:
                fmt.Println("goroutine running")
                time.Sleep(500 * time.Millisecond)
            }
        }
    }()
 
    time.Sleep(2 * time.Second)
    cancel()
    wg.Wait()
}

在這個(gè)示例中,我們創(chuàng)建了一個(gè)帶有取消功能的Context,然后將其傳遞給goroutine。在goroutine中,我們使用select語(yǔ)句來(lái)監(jiān)聽Context的Done方法,如果Context被取消,我們將會(huì)取消goroutine的執(zhí)行。在主函數(shù)中,我們使用time.Sleep函數(shù)來(lái)模擬程序運(yùn)行過(guò)程中的某個(gè)時(shí)刻需要取消goroutine的執(zhí)行,然后調(diào)用Context的Cancel方法來(lái)取消goroutine的執(zhí)行。

3.3 資源管理

在某些情況下,我們需要對(duì)goroutine使用的資源進(jìn)行管理,以避免資源泄露或者出現(xiàn)競(jìng)爭(zhēng)條件等問(wèn)題。使用Context可以幫助我們更好地管理goroutine使用的資源。我們可以將資源與Context關(guān)聯(lián)起來(lái),然后將Context傳遞給goroutine。當(dāng)goroutine完成執(zhí)行后,我們可以使用Context來(lái)釋放資源或者進(jìn)行其他的資源管理操作。

下面是一個(gè)簡(jiǎn)單的示例代碼:

package main
 
import (
    "context"
    "fmt"
    "sync"
    "time"
)
 
func worker(ctx context.Context, wg *sync.WaitGroup) {
    defer wg.Done()
    for {
        select {
        case <-ctx.Done():
            fmt.Println("goroutine finished")
            return
        default:
            fmt.Println("goroutine running")
            time.Sleep(500 * time.Millisecond)
        }
    }
}
 
func main() {
    ctx, cancel := context.WithCancel(context.Background())
 
    var wg sync.WaitGroup
    wg.Add(1)
    go worker(ctx, &wg)
 
    time.Sleep(2 * time.Second)
    cancel()
    wg.Wait()
}

在這個(gè)示例中,我們創(chuàng)建了一個(gè)帶有取消功能的Context,然后將其傳遞給goroutine。在goroutine中,我們使用select語(yǔ)句來(lái)監(jiān)聽Context的Done方法,如果Context被取消,我們將會(huì)取消goroutine的執(zhí)行。在主函數(shù)中,我們使用time.Sleep函數(shù)來(lái)模擬程序運(yùn)行過(guò)程中的某個(gè)時(shí)刻需要取消goroutine的執(zhí)行,然后調(diào)用Context的Cancel方法來(lái)取消goroutine的執(zhí)行。

到此這篇關(guān)于Golang中常見的三種并發(fā)控制方式使用小結(jié)的文章就介紹到這了,更多相關(guān)Go并發(fā)控制方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文帶你玩轉(zhuǎn)Golang Prometheus Eexporter開發(fā)

    一文帶你玩轉(zhuǎn)Golang Prometheus Eexporter開發(fā)

    本文分兩大塊,一是搞清楚prometheus四種類型的指標(biāo)Counter,Gauge,Histogram,Summary用golang語(yǔ)言如何構(gòu)造這4種類型對(duì)應(yīng)的指標(biāo),二是搞清楚修改指標(biāo)值的場(chǎng)景和方式,感興趣的可以了解一下
    2023-02-02
  • 簡(jiǎn)單談?wù)凣olang中的字符串與字節(jié)數(shù)組

    簡(jiǎn)單談?wù)凣olang中的字符串與字節(jié)數(shù)組

    這篇文章主要給大家介紹了關(guān)于Golang中字符串與字節(jié)數(shù)組的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用Golang具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Go語(yǔ)言中調(diào)用外部命令的方法總結(jié)

    Go語(yǔ)言中調(diào)用外部命令的方法總結(jié)

    在工作中,我們時(shí)不時(shí)地會(huì)需要在Go中調(diào)用外部命令。本文為大家總結(jié)了Go語(yǔ)言中調(diào)用外部命令的幾種姿勢(shì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-11-11
  • 詳解Go 1.22 for循環(huán)的兩處重要更新

    詳解Go 1.22 for循環(huán)的兩處重要更新

    這篇文章主要詳細(xì)介紹了Go 1.22 for循環(huán)的兩處重要更新,Go 1.22 版本于 2024 年 2 月 6 日發(fā)布,引入了幾個(gè)重要的特性和改進(jìn),在語(yǔ)言層面上,這個(gè)版本對(duì) for 循環(huán)進(jìn)行了兩處更新,本文將會(huì)對(duì) for 循環(huán)的兩個(gè)更新進(jìn)行介紹,需要的朋友可以參考下
    2024-02-02
  • golang構(gòu)建HTTP服務(wù)的實(shí)現(xiàn)步驟

    golang構(gòu)建HTTP服務(wù)的實(shí)現(xiàn)步驟

    其實(shí)很多框架都是在 最簡(jiǎn)單的http服務(wù)上做擴(kuò)展的的,基本上都是遵循h(huán)ttp協(xié)議,本文主要介紹了golang構(gòu)建HTTP服務(wù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Go語(yǔ)言單線程運(yùn)行也會(huì)有的并發(fā)問(wèn)題解析

    Go語(yǔ)言單線程運(yùn)行也會(huì)有的并發(fā)問(wèn)題解析

    這篇文章主要為大家介紹了Go語(yǔ)言單線程運(yùn)行的并發(fā)問(wèn)題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Mac下Vs code配置Go語(yǔ)言環(huán)境的詳細(xì)過(guò)程

    Mac下Vs code配置Go語(yǔ)言環(huán)境的詳細(xì)過(guò)程

    這篇文章給大家介紹Mac下Vs code配置Go語(yǔ)言環(huán)境的詳細(xì)過(guò)程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2021-07-07
  • Golang極簡(jiǎn)入門教程(一):基本概念

    Golang極簡(jiǎn)入門教程(一):基本概念

    這篇文章主要介紹了Golang極簡(jiǎn)入門教程(一):基本概念,本文講解了Golang的基本知識(shí)、基礎(chǔ)語(yǔ)法、相關(guān)術(shù)語(yǔ)等,需要的朋友可以參考下
    2014-10-10
  • Go中的條件語(yǔ)句Switch示例詳解

    Go中的條件語(yǔ)句Switch示例詳解

    Go的switch的基本功能和C、Java類似,switch 語(yǔ)句用于基于不同條件執(zhí)行不同動(dòng)作,每一個(gè) case 分支都是唯一的,從上至下逐一測(cè)試,直到匹配為止,對(duì)Go條件語(yǔ)句Switch相關(guān)知識(shí)感興趣的朋友一起看看吧
    2021-08-08
  • Go實(shí)現(xiàn)后臺(tái)任務(wù)調(diào)度系統(tǒng)的實(shí)例代碼

    Go實(shí)現(xiàn)后臺(tái)任務(wù)調(diào)度系統(tǒng)的實(shí)例代碼

    平常我們?cè)陂_發(fā)API的時(shí)候,前端傳遞過(guò)來(lái)的大批數(shù)據(jù)需要經(jīng)過(guò)后端處理,如果后端處理的速度快,前端響應(yīng)就快,反之則很慢,影響用戶體驗(yàn),為了解決這一問(wèn)題,需要我們自己實(shí)現(xiàn)后臺(tái)任務(wù)調(diào)度系統(tǒng),本文將介紹如何用Go語(yǔ)言實(shí)現(xiàn)后臺(tái)任務(wù)調(diào)度系統(tǒng),需要的朋友可以參考下
    2023-06-06

最新評(píng)論