i have to invoke goroutuine /thread from a loop. Because of the loop, there are many go routines executes in parallel. If any routine/thread executed successfully, then i have to stop all other thread/routine.
Is there any way to implement this?
i have to invoke goroutuine /thread from a loop. Because of the loop, there are many go routines executes in parallel. If any routine/thread executed successfully, then i have to stop all other thread/routine.
Is there any way to implement this?
You can use quit channels in addition to context as answered by Burak.
package main
import (
"fmt"
"math/rand"
"time"
)
func foo(channel, quit chan string, i int) {
channel <- fmt.Sprintf("goroutine %d started!", i)
for {
rand.Seed(time.Now().UnixNano())
time.Sleep(time.Duration(rand.Intn(500)+500) * time.Millisecond)
quit <- fmt.Sprintf("goRoutine %d completed!", i)
}
}
func main() {
channel := make(chan string)
quit := make(chan string)
for i := 0; i < 3; i++ {
go foo(channel, quit, i)
}
for {
select {
case update:= <-channel:
fmt.Println(update)
case quit:= <-quit:
fmt.Println(quit)
return
}
}
}
You can use a context:
ctx, cancel:= context.WithCancel(context.Background())
for ... {
go func() {
defer cancel() // cancel context once this goroutine ends
doStuff(ctx)
}()
}
You have to check context cancellation in the goroutines:
func doStuff(ctx context.Context) {
...
if ctx.Err()!=nil {
// Canceled, return
return
}
...
}
This will not guarantee that once the context is canceled other goroutines will end immediately, however it guarantees that, if you check for context cancellation correctly, all goroutines will end eventually.
You could use a context and an errgroup. Something along the lines of...
package main
import (
"context"
"fmt"
"math/rand"
"os"
"time"
"golang.org/x/sync/errgroup"
)
func doStuff(ctx context.Context, i int) error {
count := 0
for ctx.Err() == nil {
// do the stuff
time.Sleep(time.Millisecond * time.Duration(rand.Intn(500)))
count++
if count > 6 { // error condition
fmt.Fprintf(os.Stdout, "%v reached count %v\n", i, count)
return fmt.Errorf("Error %v, count %v\n", i, count)
}
}
fmt.Fprintf(os.Stdout, "Killed %v @ count %v\n", i, count)
return ctx.Err()
}
func main() {
rand.Seed(int64(time.Now().Nanosecond()))
ctxWc, _ := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctxWc)
for i := 0; i < 5; i++ {
i := i
g.Go(func() error {
return doStuff(ctx, i)
})
}
err := g.Wait()
fmt.Println("The End")
if err != nil {
fmt.Println(err)
}
}