【问题标题】:How to kill running goroutines from outside? [duplicate]如何从外部杀死正在运行的 goroutine? [复制]
【发布时间】:2020-01-06 06:42:27
【问题描述】:

我有一个 goroutine 池,我想从外部杀死其中的一个。

感谢您的帮助

【问题讨论】:

  • 例程必须自行终止。它可以从通过go 关键字调用的函数返回,也可以调用runtime.Goexit()

标签: go goroutine


【解决方案1】:

你不能“杀死”一个 goroutine。您可以使用其中一种同步原语或上下文来告诉 goroutine 您希望它结束​​。

ctx,cancel:=context.WithCancel(context.Background())
go  func(ctx context.Context) {
   for {
      select {
         case <-ctx.Done():
           return 
         default
       }
       // Do stuff
     }
}(ctx) 
...
// Tell that goroutine to stop
cancel()

您也可以使用 sync.atomic:

die:=make([]int32,nGoroutines)

go func(i int) {
   if atomic.LoadInt32(&die[i])==1 {
       return
   }
   // Do stuff
   if atomic.LoadInt32(&die[i])==1 {
       return
   }
   // Do more stuff
}(0) // 0'th goroutine

...
// Tell goroutine n to stop
atomic.StoreInt32(&die[n],1)

【讨论】:

    【解决方案2】:

    我找到了答案。有一个名为 Context 的概念,它携带跨越 API 边界和进程之间的截止日期、取消信号和其他请求范围的值。这是示例代码:

    type Job struct {
        ID int
        Context context.Context
        Cancel context.CancelFunc
    }
    var jobs = make(map[int] Job)
    
    func worker(ctx context.Context, index int) {
       fmt.Printf("starting job with id %d\n", index)
       <-ctx.Done()
    }
    
    func main() {
     var err error
    
     id := 0
     r := gin.Default()
    
     r.POST("/start", func(c *gin.Context) {
        var job Job
        err := json.NewDecoder(c.Request.Body).Decode(&job)
        if err != nil{ fmt.Println(err)}
        ctx, cancel := context.WithCancel(context.Background())
        job.ID = id
        job.Context = ctx
        job.Cancel = cancel
        jobs[job.ID] = job
        c.JSON(http.StatusOK, gin.H{"message": "job received"})
        go worker(ctx, job.ID)
        id ++
     })
    
     r.GET("/cancel/:id", func(c *gin.Context) {
        id := c.Param("id")
        idInt, err := strconv.Atoi(id)
        if err != nil {fmt.Println(err)}
        jobs[idInt].Cancel()
     })
    
      err = endless.ListenAndServe(":8080", r)
      if err != nil{ fmt.Printf("Could not run server : %v", err.Error())}
     }
    

    【讨论】:

    • 这是一个使用 API 终止 goroutine 的示例
    • 如果worker调用了某个函数,而该函数没有返回,worker不会退出。函数本身需要不时检查它是否应该退出。当函数完成后,它可以返回;无需在ctx.Done() 频道上等待,因为不会发送任何内容:它只会被关闭。
    【解决方案3】:

    你可以使用频道

    endRoutine:=  make(chan bool)
    go func() {
        <-endRoutine
    }()
    
    //To end one thread waiting on the channel
    endRoutine<-true
    

    https://play.golang.org/p/IRARfywOLZX

    如果您在循环中处理数据并且需要检查是否应该在每次迭代时退出,您可以使用开关

    go func() {
        for {
            switch {
                 case <-endRoutine:
                  return //exit
                  default:
                  break
            }
       }
    }()
    

    https://play.golang.org/p/18eOHpilnFi

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-12
      • 1970-01-01
      • 2013-11-01
      • 2014-03-08
      • 1970-01-01
      • 2013-02-04
      • 1970-01-01
      • 2018-12-10
      相关资源
      最近更新 更多