为什么Golang中的Network IO会增加线程使用量?

时间:2018-12-31 04:39:57

标签: go

我创建了一个测试程序来检查我对Golang如何处理网络IO的理解。 下面的程序创建1000个goroutine,在每个goroutine中,它将发出一个网络IO请求。

当我尝试监视正在使用的线程数时,它最多增加了400个线程。 我曾经使用top命令进行监视,我的理解是针对网络io Golang使用netpoll(即async io)。

如果我的理解是错误的,请纠正我。

操作系统:macos高山脉

Go版本:go1.11.2 darwin / amd64

package main

import (
    "encoding/json"
    "log"
    "net/http"
    "sync"
    "time"
)

func main() {
    timeout := time.Duration(5 * time.Second)
    client := http.Client{
        Timeout: timeout,
    }
    var wg sync.WaitGroup

    start := time.Now()
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go callAPI(&wg, client)
    }
    wg.Wait()
    log.Println(time.Since(start))
}

func callAPI(wg *sync.WaitGroup, client http.Client) {
    defer wg.Done()
    url := `JSON-API-URL-OF-YOUR-CHOICE` // Please enter a valid json api url.
    request, err := http.NewRequest("GET", url, nil)
    if err != nil {
        log.Fatalln(err)
    }

    resp, err := client.Do(request)
    if err != nil {
        log.Fatalln(err)
    }

    var result map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&result)
    defer resp.Body.Close()

    log.Println(result)
}

1 个答案:

答案 0 :(得分:3)

在系统IO调用中阻塞线程时,Go可能会创建一个新线程以允许其他goroutine继续运行。这有一个很好的解释:https://povilasv.me/go-scheduler/

  

当您的goroutine进行阻塞的系统调用时,会发生有趣的事情。阻塞的系统调用将被拦截,如果有要运行的G,运行时将把线程与P分离,并创建一个新的OS线程(如果不存在空闲线程)来服务该处理器。

因此,与其拥有少量线程并占用0%的CPU资源,因为所有线程都被阻塞,等待阻塞的系统调用返回,而是将这些线程放在一边并旋转新的线程,因此非阻塞的goroutine等待阻塞的系统调用返回时可以做他们的工作。