Это y конкретные подпрограммы, которые вы пытаетесь отследить, или какие-либо y вне x? Каковы критерии?
Обновление:
1. Если у вас есть контроль над какими-либо критериями, выберите matching y
go-рутины:
Вы можете сделать wp.wg.Add(1)
и wp.wg.Done()
изнутри группы, основываясь на вашем условии, передав его в качестве аргумента-указателя в программу, если ваше состояние не может быть проверено за пределами программы.
Что-то вроде приведенного ниже примера кода. Будет более точным, если вы предоставите более подробную информацию о том, что вы пытаетесь сделать.
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
:
Исходя из вашего комментария, у вас нет контроля / желания выбирать какие-либо конкретные программы, кроме тех, которые заканчиваются первыми. Если вы хотите сделать это универсальным способом, вы можете использовать приведенную ниже пользовательскую реализацию 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. Вы также можете забить в context
с 2, чтобы гарантировать, что оставшиеся goroutines не просачиваются
Возможно, вы не сможете запустить это на play.golang, так как он долго спит.
Ниже приведен пример вывода:
(обратите внимание, что может быть больше y = 3 goroutines, отмечающих Done, но вы ждете только до 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
Воспроизведение ссылок
- https://play.golang.org/p/l5i6X3GClBq
- https://play.golang.org/p/Bcns0l9OdFg
- https://play.golang.org/p/rkGSLyclgje