我之前用過(guò) goroutine 的 sync.WaitGroup,但是我想控制 goroutine 的并發(fā),所以我用并發(fā)限制編寫我的等待組,例如:package wglimitimport ( "sync")// WaitGroupLimit ...type WaitGroupLimit struct { ch chan int wg *sync.WaitGroup}// New ...func New(size int) *WaitGroupLimit { if size <= 0 { size = 1 } return &WaitGroupLimit{ ch: make(chan int, size), // buffer chan to limit concurrency wg: &sync.WaitGroup{}, }}// Add ...func (wgl *WaitGroupLimit) Add(delta int) { for i := 0; i < delta; i++ { wgl.ch <- 1 wgl.wg.Add(1) }}// Done ...func (wgl *WaitGroupLimit) Done() { wgl.wg.Done() <-wgl.ch}// Wait ...func (wgl *WaitGroupLimit) Wait() { close(wgl.ch) wgl.wg.Wait()}然后我用它來(lái)控制 goroutine 并發(fā),例如:jobs := ["1", "2", "3", "4"] // some jobs// wg := sync.WaitGroup{} // have no concurrency limitwg := wglimit.New(2) // limit 2 goroutinefor _, job := range jobs { wg.Add(1) go func(job string) { // job worker defer wg.Done() }(job)}wg.Wait()運(yùn)行時(shí)看起來(lái)像工作。但測(cè)試失?。簆ackage wglimitimport ( "runtime" "testing" "time")func TestGoLimit(t *testing.T) { var limit int = 5 wglimit := New(limit) for i := 0; i < 10000; i++ { wglimit.Add(1) go func() { defer wglimit.Done() time.Sleep(time.Millisecond) if runtime.NumGoroutine() > limit+2 { println(runtime.NumGoroutine()) // will print 9 , cocurrent limit fail ? t.Errorf("FAIL") } }() } wglimit.Wait()}測(cè)試時(shí),goroutine 數(shù)量大于我的限制,似乎并流限制失敗。我的 WaitGroupLimit 代碼有什么問(wèn)題,為什么?
1 回答

心有法竹
TA貢獻(xiàn)1866條經(jīng)驗(yàn) 獲得超5個(gè)贊
我的 WaitGroupLimit 代碼 [...] 有什么問(wèn)題嗎?
不。
問(wèn)題是runtime.NumGoroutine()
沒(méi)有做你認(rèn)為它做的事情。它計(jì)算所有goroutine,即不僅是您啟動(dòng)的 goroutine,還包括運(yùn)行時(shí)使用的 goroutine,例如并發(fā)垃圾收集。因此,NumGoroutine 高于您的限制。
你的代碼很好,你的測(cè)試不是。不要試圖在測(cè)試和測(cè)試你的代碼真正做的事情時(shí)變得聰明:它會(huì)一直阻塞,Add
直到有限的資源可用。測(cè)試它而不是 goroutine 計(jì)數(shù),它只是測(cè)試中所需行為的(壞)代理。
- 1 回答
- 0 關(guān)注
- 120 瀏覽
添加回答
舉報(bào)
0/150
提交
取消