#go
#Вперед
Вопрос:
Я использовал sync.WaitGroup с goroutine раньше, но я хочу контролировать параллелизм goroutine,
итак, я пишу свою waitgroup с ограничением параллелизма, например:
package wglimit
import (
"sync"
)
// WaitGroupLimit ...
type WaitGroupLimit struct {
ch chan int
wg *sync.WaitGroup
}
// New ...
func New(size int) *WaitGroupLimit {
if size <= 0 {
size = 1
}
return amp;WaitGroupLimit{
ch: make(chan int, size), // buffer chan to limit concurrency
wg: amp;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()
}
И затем я использую это для управления параллелизмом goroutine, например:
jobs := ["1", "2", "3", "4"] // some jobs
// wg := sync.WaitGroup{} // have no concurrency limit
wg := wglimit.New(2) // limit 2 goroutine
for _, job := range jobs {
wg.Add(1)
go func(job string) {
// job worker
defer wg.Done()
}(job)
}
wg.Wait()
И, похоже, это сработало при запуске.
Но тест не удался:
package wglimit
import (
"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()
}
При тестировании числа процедур больше моего предела, похоже, что предел совместного тока не выполняется.
Что-то не так с моим кодом WaitGroupLimit и почему?
Комментарии:
1. Если вы использовали
fmt.Print("spawned")
с задержкой в 1 секунду, это лучше продемонстрировало бы, есть ли у вас проблема или нет. Ваша текущая проверка на основеruntime
не выглядит надежной (у нее, по крайней мере, есть условие гонки).2. каково ожидаемое поведение этого механизма? если вы попытаетесь выполнить запись в канал, который заполнен, то это выдаст ошибку. Это то, что вы ищете
Ответ №1:
Что-нибудь не так с моим кодом WaitGroupLimit […]?
Нет.
Проблема в том, runtime.NumGoroutine()
что она делает не то, что вы, кажется, думаете. Он учитывает все подпрограммы, то есть не только те, которые вы запускаете, но и те, которые использует сама среда выполнения, например, для одновременной сборки мусора. Таким образом, NumGoroutine превышает ваш лимит.
Ваш код в порядке, ваш тест — нет. Не пытайтесь поумнеть в тестировании и проверить, что на самом деле делает ваш код: он блокируется Add
до тех пор, пока не будет доступен ограниченный ресурс. Проверьте это, а не количество подпрограмм, которое является просто (плохим) прокси для желаемого поведения в вашем тесте.