Goroutine Timeout

前端 未结 2 770
生来不讨喜
生来不讨喜 2021-01-29 00:34
type Response struct {
  data   interface{}
  status bool
}

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

  go func() {
    data, status := findCicC         


        
相关标签:
2条回答
  • 2021-01-29 00:51

    If you want to, you can create your own timeout system for arbitrary work by having a single receive operation on the channel (in the main goroutine), and whichever other goroutine reaches its send operation first -- the time.Sleep or the one doing actual work -- wins.

    Here's a complete runnable example/simulation. Adjust timeout and delay values to simulate different scenarios. The channel is unbuffered, and is closed after a single value is read to allow the other goroutine to exit on send.

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

    A buffered channel would work too. And you could accomplish the same thing with a sync.WaitGroup where you only call Add once and then close the channel after wg.Wait().

    That said, I suggest trying JimB's solution of using a Context timeout, as it probably works for your use case and is a less complicated solution.

    0 讨论(0)
  • 2021-01-29 00:55

    You control cancelation of http requests with a context.Context.

    // 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))
    
    0 讨论(0)
提交回复
热议问题