协程超时

Goroutine Timeout

type Response struct {
  data   interface{}
  status bool
}

func Find() (interface{}, bool) {
  ch := make(chan Response, 1)

  go func() {
    data, status := findCicCode()
    ch <- Response{data: data, status: status}
  }()

  select {
  case response := <-ch:
    return response.data, response.status
  case <-time.After(50 * time.Millisecond):
    return "Request timed out", false
  }
}

所以,我有上面的功能。基本上 findCicCode() 函数调用在内部对外部服务进行 3 个 http 调用。我在这里为这 3 个 http 调用添加了组合超时。不能在我的情况下设置个人超时。但如果超过超时,它仍然会在后台进行 api 调用。

我不确定这里是否有 goroutine 泄漏。如果超时,有没有办法取消这些 https 请求?

您可以使用 context.Context.

控制取消 http 请求
// create a timeout or cancelation context to suit your requirements
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

req, err := http.NewRequest("GET", location, nil)

// add the context to each request and they will be canceled in unison
resp, err := http.Do(req.WithContext(ctx))

如果你愿意,你可以通过在通道上(在主 goroutine 中)进行单个接收操作来为任意工作创建自己的超时系统,并且无论哪个 goroutine 先到达它的发送操作 - time.Sleep 或实际工作的人获胜。

这是一个完整的可运行文件 example/simulation。调整超时和延迟值以模拟不同的场景。该通道是无缓冲的,并在读取单个值后关闭以允许另一个 goroutine 在发送时退出。

package main

import(
    "fmt"
    "time"
)

type Response struct {
    Data        []byte
    Status      int
}

func Wait(s int) {
    time.Sleep(time.Duration(s) * time.Second)
}

func FindWrapper(ch chan Response, delay int) {
    // Put real find stuff here...

    // Dummy response after wait for testing purposes
    Wait(delay)
    ch <- Response{[]byte("Some data..."), 200}
}

func main() {
    timeout := 3
    delay := 4
    ch := make(chan Response)

    // whoever sends to ch first wins...
    go func() {
        Wait(timeout)
        ch <- Response{}
    }()
    go FindWrapper(ch, delay)

    r := <-ch
    close(ch)
    if r.Data == nil {
        r.Status = 500 // or whatever you want for timeout status
    }
    fmt.Printf("Data: %s  Status: %d\n", string(r.Data), r.Status)
}

缓冲通道也可以。你可以用 sync.WaitGroup 完成同样的事情,你只调用一次添加然后在 wg.Wait().

之后关闭频道

也就是说,我建议尝试使用 JimB 的 Context 超时解决方案,因为它可能适用于您的用例并且是一个不太复杂的解决方案。