11

我想在超时时停止执行 goroutine。但它似乎对我不起作用。我正在使用iris框架。

  type Response struct {
    data   interface{}
    status bool
  }

  func (s *CicService) Find() (interface{}, bool) {

    ch := make(chan Response, 1)

    go func() {
      time.Sleep(10 * time.Second)

      fmt.Println("test")
      fmt.Println("test1")

      ch <- Response{data: "data", status: true}
    }()

    select {
    case <-ch:
      fmt.Println("Read from ch")
      res := <-ch
      return res.data, res.status
    case <-time.After(50 * time.Millisecond):
      return "Timed out", false
    }

  }

输出:

 Timed out
 test
 test1

预期输出:

 Timed out

有人可以指出这里缺少什么吗?它确实超时但仍然运行 goroutine 来打印testtest1. 我只想在超时后立即停止执行 goroutine。

4

3 回答 3

14

没有好的方法可以在执行过程中“中断”goroutine 的执行。

Go 使用并发的 fork-join 模型,这意味着您“fork”创建一个新的 goroutine,然后在到达“join point”之前无法控制该 goroutine 的调度方式。连接点是多个 goroutine 之间的某种同步。例如在通道上发送一个值。

以您的具体示例为例,这一行:

ch <- Response{data: "data", status: true}

...将能够发送该值,无论如何,因为它是一个缓冲通道。但是你已经创建了超时:

case <-time.After(50 * time.Millisecond):
  return "Timed out", false

这些超时在频道的“接收者”或“阅读者”上,而不是在“发送者”上。如本答案顶部所述,如果不使用一些同步技术,就无法中断 goroutine 的执行。

因为超时发生在从通道“读取”的 goroutine 上,所以没有什么可以阻止在通道上发送的 goroutine 的执行。

于 2018-05-28T17:58:29.587 回答
12

控制goroutine 处理的最佳方法是上下文(std go 库)。

您可以取消 goroutine 中的某些内容并停止执行,而不会出现 goroutine 泄漏

这里是一个简单的例子,在你的情况下超时取消。

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

ch := make(chan Response, 1)

go func() {
    time.Sleep(1 * time.Second)

    select {
    default:
        ch <- Response{data: "data", status: true}
    case <-ctx.Done():
        fmt.Println("Canceled by timeout")
        return
    }
}()

select {
case <-ch:
    fmt.Println("Read from ch")
case <-time.After(500 * time.Millisecond):
    fmt.Println("Timed out")
}
于 2018-05-29T08:21:03.873 回答
0

您有一个 gouroutine 泄漏,您必须处理一些已完成的操作以在超时之前返回 goroutine,如下所示:

func (s *CicService) Find() (interface{}, bool) {

    ch := make(chan Response, 1)
    done := make(chan struct{})
    go func() {
        select {
        case <-time.After(10 * time.Second):
        case <-done:
            return
        }
        fmt.Println("test")
        fmt.Println("test1")
        ch <- Response{data: "data", status: true}
    }()
    select {
    case res := <-ch:
        return res.data, res.status
    case <-time.After(50 * time.Millisecond):
        done <- struct{}{}
        return "Timed out", false
    }

}
于 2018-06-28T11:26:27.310 回答