【问题标题】:how to stop multiple go routines如何停止多个 goroutine
【发布时间】:2021-08-01 17:11:03
【问题描述】:

我必须从循环中调用 goroutuine /thread。由于循环,有许多 go 例程并行执行。如果任何例程/线程成功执行,那么我必须停止所有其他线程/例程。

有什么方法可以实现吗?

【问题讨论】:

    标签: go goroutine glide-golang


    【解决方案1】:

    您可以使用上下文:

    ctx, cancel:= context.WithCancel(context.Background())
    for ... {
       go func() {
          defer cancel() // cancel context once this goroutine ends
          doStuff(ctx)
       }()
    }
    

    您必须在 goroutines 中检查上下文取消:

    func doStuff(ctx context.Context) {
       ...
       if ctx.Err()!=nil {
           // Canceled, return
           return
       }
      ...
    }
    

    这并不能保证一旦上下文被取消,其他 goroutine 将立即结束,但是它保证,如果您正确检查上下文取消,所有 goroutine 将最终结束。

    【讨论】:

      【解决方案2】:

      除了 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
              }
          }
      }
      
      

      【讨论】:

        【解决方案3】:

        您可以使用上下文和错误组。 类似的东西......

        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)
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2011-10-12
          • 2017-07-19
          • 2018-04-24
          • 2018-02-19
          • 2019-08-10
          • 2020-02-14
          • 1970-01-01
          • 2018-08-14
          • 1970-01-01
          相关资源
          最近更新 更多