刚回到 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 更长?????