亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

go 例程子集上的等待組

go 例程子集上的等待組

Go
RISEBY 2023-03-29 17:30:41
我遇到的情況是,主要的 go 例程將創建“x”go 例程。但它只對要完成的“y”( y < x ) go routines 感興趣。我希望使用 Waitgroup。但是 Waitgroup 只允許我等待所有的例程。例如,我不能這樣做,1. wg.Add (y) 2 create "x" go routines. These routines will call wg.Done() when finished.  3. wg. Wait()當 y+1 go 例程調用 wg.Done() 時會出現恐慌,因為 wg 計數器變為負值。我當然可以使用渠道來解決這個問題,但我對 Waitgroup 是否能解決這個問題感興趣。
查看完整描述

3 回答

?
米琪卡哇伊

TA貢獻1998條經驗 獲得超6個贊

sync.WaitGroup這是一個簡單的計數器,其Wait方法將阻塞直到計數器值達到零。它旨在允許您在允許主要執行流程繼續進行之前阻止(或加入)多個 goroutine。

的界面WaitGroup對于您的用例而言沒有足夠的表現力,也不是設計為。特別是,您不能通過簡單地調用wg.Add(y)(where y < x) 來天真地使用它。wg.Done第 (y+1)goroutine調用將導致 panic,因為等待組具有負內部值是錯誤的。此外,我們不能通過觀察 ; 的內部計數器值來“聰明”?WaitGroup。這會破壞抽象,無論如何,它的內部狀態不會被導出。


實現你自己的!

您可以根據下面的代碼使用一些渠道自己實現相關邏輯。從控制臺觀察,啟動了 10 個 goroutine,但在兩個完成后,我們 fallthrough 繼續在 main 方法中執行。

package main


import (

? ? "fmt"

? ? "time"

)


// Set goroutine counts here

const (

? ? // The number of goroutines to spawn

? ? x = 10

? ? // The number of goroutines to wait for completion

? ? // (y <= x) must hold.

? ? y = 2

)


func doSomeWork() {

? ? // do something meaningful

? ? time.Sleep(time.Second)

}


func main() {

? ? // Accumulator channel, used by each goroutine to signal completion.

? ? // It is buffered to ensure the [y+1, ..., x) goroutines do not block

? ? // when sending to the channel, which would cause a leak. It will be

? ? // garbage collected when all goroutines end and the channel falls

? ? // out of scope. We receive y values, so only need capacity to receive

? ? // (x-y) remaining values.

? ? accChan := make(chan struct{}, x-y)


? ? // Spawn "x" goroutines

? ? for i := 0; i < x; i += 1 {

? ? ? ? // Wrap our work function with the local signalling logic

? ? ? ? go func(id int, doneChan chan<- struct{}) {

? ? ? ? ? ? fmt.Printf("starting goroutine #%d\n", id)

? ? ? ? ? ? doSomeWork()

? ? ? ? ? ? fmt.Printf("goroutine #%d completed\n", id)


? ? ? ? ? ? // Communicate completion of goroutine

? ? ? ? ? ? doneChan <- struct{}{}

? ? ? ? }(i, accChan)

? ? }


? ? for doneCount := 0; doneCount < y; doneCount += 1 {

? ? ? ? <-accChan

? ? }


? ? // Continue working

? ? fmt.Println("Carrying on without waiting for more goroutines")

}

避免泄漏資源

由于這不會等待 [y+1, ..., x) goroutines 完成,因此您應該特別注意函數doSomeWork以消除或最小化工作可能無限期阻塞的風險,這也會導致泄漏。在可能的情況下,消除無限期阻塞 I/O(包括通道操作)或陷入無限循環的可能性。


context當不再需要它們的結果來中斷執行時,您可以使用 a向其他 goroutine 發出信號。



查看完整回答
反對 回復 2023-03-29
?
HUH函數

TA貢獻1836條經驗 獲得超4個贊

WaitGroup實際上并不等待 goroutines,它一直等到其內部計數器達到零。如果你只有Add()你關心的 goroutines 的數量,并且你只調用Done()你關心的那些 goroutines,那么Wait()只會阻塞直到你關心的那些 goroutines 完成。您可以完全控制邏輯和流程,對WaitGroup“允許”的內容沒有任何限制。



查看完整回答
反對 回復 2023-03-29
?
紅糖糍粑

TA貢獻1815條經驗 獲得超6個贊

這些是您要跟蹤的特定 y 例程,還是 x 中的任何 y?標準是什么?


更新:


1. 如果您可以控制任何標準來選擇matching ygo-routines:


wp.wg.Add(1)如果無法wp.wg.Done()在 goroutine 外部檢查您的條件,則可以通過將其作為指針參數傳遞給 goroutine 來根據您的條件從 goroutine 內部執行和操作。


類似于下面的示例代碼。如果您提供有關您正在嘗試做的事情的更多詳細信息,將能夠更具體。


func sampleGoroutine(z int, b string, wg *sync.WaitGroup){


? ? defer func(){

? ? ? ? if contition1{

? ? ? ? ? ? wg.Done()

? ? ? ? }

? ? }


? ? if contition1 {

? ? ? ? wg.Add(1)

? ? ? ? //do stuff

? ? }

}


func main() {

? ? wg := sync.WaitGroup{}

? ? for i := 0; i < x; i++ {

? ? ? ? go sampleGoroutine(1, "one", &wg)

? ? }

? ? wg.Wait()

}

2. 如果你無法控制哪些,只想要first y:


根據您的評論,您無法控制/希望選擇任何特定的 goroutine,而是選擇最先完成的 goroutine。如果您想以通用方式執行此操作,則可以使用適合您的用例的以下自定義 waitGroup 實現。(不過,它不是復制安全的。也沒有/需要 wg.Add(int) 方法)


type CountedWait struct {

? ? wait? chan struct{}

? ? limit int

}


func NewCountedWait(limit int) *CountedWait {

? ? return &CountedWait{

? ? ? ? wait:? make(chan struct{}, limit),

? ? ? ? limit: limit,

? ? }

}


func (cwg *CountedWait) Done() {

? ? cwg.wait <- struct{}{}

}


func (cwg *CountedWait) Wait() {

? ? count := 0

? ? for count < cwg.limit {

? ? ? ? <-cwg.wait

? ? ? ? count += 1

? ? }

}

可以按如下方式使用:


func sampleGoroutine(z int, b string, wg *CountedWait) {


? ? success := false


? ? defer func() {

? ? ? ? if success == true {

? ? ? ? ? ? fmt.Printf("goroutine %d finished successfully\n", z)

? ? ? ? ? ? wg.Done()

? ? ? ? }

? ? }()


? ? fmt.Printf("goroutine %d started\n", z)

? ? time.Sleep(time.Second)


? ? if rand.Intn(10)%2 == 0 {

? ? ? ? success = true

? ? }

}


func main() {

? ? x := 10

? ? y := 3

? ? wg := NewCountedWait(y)


? ? for i := 0; i < x; i += 1 {

? ? ? ? // Wrap our work function with the local signalling logic

? ? ? ? go sampleGoroutine(i, "something", wg)

? ? }


? ? wg.Wait()


? ? fmt.Printf("%d out of %d goroutines finished successfully.\n", y, x)

}

3. 你也可以加入context2 以確保剩余的 goroutines 不會泄漏 你可能無法在 play.golang 上運行它,因為它有一些長時間的休眠。


下面是一個示例輸出:(注意,可能有超過 y=3 個 goroutines 標記完成,但你只等到 3 個完成)



goroutine 9 started

goroutine 0 started

goroutine 1 started

goroutine 2 started

goroutine 3 started

goroutine 4 started

goroutine 5 started

goroutine 5 marking done

goroutine 6 started

goroutine 7 started

goroutine 7 marking done

goroutine 8 started

goroutine 3 marking done

continuing after 3 out of 10 goroutines finished successfully.

goroutine 9 will be killed, bcz cancel

goroutine 8 will be killed, bcz cancel

goroutine 6 will be killed, bcz cancel

goroutine 1 will be killed, bcz cancel

goroutine 0 will be killed, bcz cancel

goroutine 4 will be killed, bcz cancel

goroutine 2 will be killed, bcz cancel

查看完整回答
反對 回復 2023-03-29
  • 3 回答
  • 0 關注
  • 153 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號