并发请求时HTTP请求超时

时间:2020-06-26 16:27:16

标签: http go

如果我在执行HTTP请求时添加客户端超时,实际上会发生什么?

我的代码就是这样

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
    "sync"
    "time"

    "github.com/vbauerster/mpb"
    "github.com/vbauerster/mpb/decor"
)

type response struct {
    Header header `json:"header"`
    // Data   data   `json:"data"`
}

type header struct {
    TotalData int `json:"total_data"`
}

type data struct {
    Product []products `json:"products"`
}

type products struct {
    Ads ads `json:"ads"`
}

type ads struct {
    ID string `json:"id"`
}

func main() {

    var wg sync.WaitGroup
    empty1 := 0
    empty2 := 0
    empty3 := 0
    loop := 1000
    endpoint := ""
    file, _ := os.OpenFile("file.tmp", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    log.SetOutput(file)
    p := mpb.New(mpb.WithWaitGroup(&wg))
    wg.Add(3)

    bar := p.AddBar(int64(loop),
        // override DefaultBarStyle, which is "[=>-]<+"
        mpb.BarStyle("╢▌▌░╟"),
        mpb.PrependDecorators(
            decor.Name("PB1", decor.WC{W: 3 + 1, C: decor.DidentRight}),
            decor.CountersNoUnit("%d / %d", decor.WCSyncWidth),
        ),
        mpb.AppendDecorators(decor.Percentage(decor.WC{W: 5}),
            decor.OnComplete(
                // ETA decorator with ewma age of 60
                decor.EwmaETA(decor.ET_STYLE_GO, 60), "done",
            ),
        ),
    )
    bar2 := p.AddBar(int64(loop),
        // override DefaultBarStyle, which is "[=>-]<+"
        mpb.BarStyle("╢▌▌░╟"),
        mpb.PrependDecorators(
            decor.Name("PB2", decor.WC{W: 3 + 1, C: decor.DidentRight}),
            decor.CountersNoUnit("%d / %d", decor.WCSyncWidth),
        ),
        mpb.AppendDecorators(decor.Percentage(decor.WC{W: 5}),
            decor.OnComplete(
                // ETA decorator with ewma age of 60
                decor.EwmaETA(decor.ET_STYLE_GO, 60), "done",
            ),
        ),
    )

    bar3 := p.AddBar(int64(loop),
        // override DefaultBarStyle, which is "[=>-]<+"
        mpb.BarStyle("╢▌▌░╟"),
        mpb.PrependDecorators(
            decor.Name("PB3", decor.WC{W: 3 + 1, C: decor.DidentRight}),
            decor.CountersNoUnit("%d / %d", decor.WCSyncWidth),
        ),
        mpb.AppendDecorators(decor.Percentage(decor.WC{W: 5}),
            decor.OnComplete(
                // ETA decorator with ewma age of 60
                decor.EwmaETA(decor.ET_STYLE_GO, 60), "done",
            ),
        ),
    )

    go func() {
        defer wg.Done()
        now := time.Now()
        conChan := make(chan response, loop)

        var wg2 sync.WaitGroup
        wg2.Add(1)

        go func() {
            defer wg2.Done()
            for i := 1; i <= loop; i++ {
                receiver := <-conChan
                if receiver.Header.TotalData == 0 {
                    empty1++
                }
                bar.Increment()
            }
        }()

        for i := 1; i <= loop; i++ {
            if i%50 == 0 {
                time.Sleep(1 * time.Second)
            }
            go concurent(conChan, fmt.Sprintf(endpoint, i))
        }

        wg2.Wait()
        log.Println("wg 1", time.Since(now).Seconds())
    }()

    go func() {
        defer wg.Done()
        now := time.Now()
        conChan := make(chan response, loop)

        var wg2 sync.WaitGroup
        wg2.Add(1)

        go func() {
            defer wg2.Done()
            for i := 1; i <= loop; i++ {
                receiver := <-conChan
                if receiver.Header.TotalData == 0 {
                    empty2++
                }
                bar2.Increment()
            }
        }()

        for i := 1; i <= loop; i++ {
            if i%50 == 0 {
                time.Sleep(1 * time.Second)
            }
            go concurent(conChan, fmt.Sprintf(endpoint, i))
        }

        wg2.Wait()
        log.Println("wg 2", time.Since(now).Seconds())
    }()

    go func() {
        defer wg.Done()
        now := time.Now()
        conChan := make(chan response, loop)

        var wg2 sync.WaitGroup
        wg2.Add(1)

        go func() {
            defer wg2.Done()
            for i := 1; i <= loop; i++ {
                receiver := <-conChan
                if receiver.Header.TotalData == 0 {
                    empty3++
                }
                bar3.Increment()
            }
        }()

        for i := 1; i <= loop; i++ {
            if i%50 == 0 {
                time.Sleep(1 * time.Second)
            }
            go concurent(conChan, fmt.Sprintf(endpoint, i))
        }

        wg2.Wait()
        log.Println("wg 3", time.Since(now).Seconds())
    }()
    p.Wait()

    fmt.Println("empty1:", empty1)
    fmt.Println("empty2:", empty2)
    fmt.Println("empty3:", empty3)
}

func concurent(channel chan response, url string) {

    resp := response{}

    defer func() {
        channel <- resp
    }()

    client := &http.Client{
        Timeout: 500 * time.Millisecond,
    }

    req, err := http.NewRequest("GET", url, nil)
    res, err := client.Do(req)

    if err != nil {
        log.Print(err, "1")
        return
    }
    defer res.Body.Close()

    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        log.Print(err, "2")
        return

    }
    err = json.Unmarshal(body, &resp)
    if err != nil {
        log.Print(string(body))

        return

    }

}

我很困惑,因为如果我不设置超时,那么在设置超时的情况下,如果执行相同的时间执行,我将得到更少的空结果,在这种情况下为500ms。 (大约20秒即可完成所有过程,无论有无超时)。在Go文档中说

客户端的传输通常具有内部状态(缓存的TCP 连接),因此应重新使用客户端,而不是根据需要创建客户端。客户端可以安全地被多个goroutine并发使用。

这是什么意思?我用于请求的客户端是否相同,这就是为什么设置超时时得到更多空结果的原因?

0 个答案:

没有答案