简单的 API 来处理带有和不带有并发(Go Routine)的 go 应用程序的 HTTP 请求

问题描述 投票:0回答:0

刚回到 golang 尝试并发编程,我尝试使用并发从我在本地主机上运行的简单应用程序中获取 10 个数据

所以首先我用 Gin 做了一个简单的应用程序

func main() {
    r := gin.Default()
    r.GET("/", func(ctx *gin.Context) {
        ctx.JSON(200, map[string]string{
            "msg": "hae",
        })
    })
    http.ListenAndServe(":9090", r)
}

然后,我制作了 2 个程序来使用和不使用并发获取数据 没有:

func main() {
    t := time.Now()

    // 10 request without concurrent
    fetchWithout()
    fetchWithout()
    fetchWithout()
    fetchWithout()
    fetchWithout()
    fetchWithout()
    fetchWithout()
    fetchWithout()
    fetchWithout()
    fetchWithout()
    fmt.Println("total time", time.Since(t))
}

func fetchWithout() {
    t := time.Now()

    c, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
    defer cancel()

    url := "http://localhost:9090/"
    client := &http.Client{}
    req, err := http.NewRequestWithContext(c, "GET", url, nil)
    if err != nil {
        fmt.Println(err)
    }
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println(err)
    }

    defer resp.Body.Close()
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        fmt.Println(err)
    }
    fmt.Println(string(body))
    fmt.Println(time.Since(t))
}

与:


func main() {
    t := time.Now()
    ch := make(chan string, 10)
    ctx := context.Background()

    var wg = &sync.WaitGroup{}

    wg.Add(10)
    go fetchWithGoRoutine(ctx, ch, wg)
    go fetchWithGoRoutine(ctx, ch, wg)
    go fetchWithGoRoutine(ctx, ch, wg)
    go fetchWithGoRoutine(ctx, ch, wg)
    go fetchWithGoRoutine(ctx, ch, wg)
    go fetchWithGoRoutine(ctx, ch, wg)
    go fetchWithGoRoutine(ctx, ch, wg)
    go fetchWithGoRoutine(ctx, ch, wg)
    go fetchWithGoRoutine(ctx, ch, wg)
    go fetchWithGoRoutine(ctx, ch, wg)

    wg.Wait()
    close(ch)

    fmt.Println(len(ch))

    for v := range ch {
        fmt.Println(v)
    }

    fmt.Println("total time", time.Since(t))
}

func fetchWithGoRoutine(ctx context.Context, ch chan string, wg *sync.WaitGroup) error {
    t := time.Now()

    c, cancel := context.WithTimeout(ctx, 50*time.Millisecond)
    defer cancel()

    url := "http://localhost:9090/"
    client := &http.Client{}
    req, err := http.NewRequestWithContext(c, "GET", url, nil)
    if err != nil {
        return err
    }
    resp, err := client.Do(req)
    if err != nil {
        return err
    }

    defer resp.Body.Close()
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return err
    }
    ch <- string(body)

    wg.Done()
    fmt.Println(time.Since(t))
    return nil
}

在没有 go routine 的情况下,我得到了这个结果:

{"msg":"hae"}
1.500143ms
{"msg":"hae"}
424.638µs
{"msg":"hae"}
469.86µs
{"msg":"hae"}
306.838µs
{"msg":"hae"}
226.128µs
{"msg":"hae"}
190.87µs
{"msg":"hae"}
181.057µs
{"msg":"hae"}
187.185µs
{"msg":"hae"}
240.558µs
{"msg":"hae"}
209.465µs
total time 4.042698ms

先看结果耗时1.500143ms 下一个结果需要越来越短的时间

现在通过 go routine 获取结果,我得到了这个结果:

2.108271ms
2.131273ms
2.462516ms
2.584931ms
2.529166ms
2.518011ms
2.618236ms
2.639384ms
2.863897ms
3.264948ms
10
{"msg":"hae"}
{"msg":"hae"}
{"msg":"hae"}
{"msg":"hae"}
{"msg":"hae"}
{"msg":"hae"}
{"msg":"hae"}
{"msg":"hae"}
{"msg":"hae"}
{"msg":"hae"}
total time 3.542049ms

在这里查看结果,每个请求我得到大约 2-3 毫秒。

问题是,为什么如果我对 http.request 使用 go 例程,我对每个请求的响应时间比简单的同步 http.request 更长?????

go http goroutine
© www.soinside.com 2019 - 2024. All rights reserved.