【问题标题】:Golang asynchronous and CPU usageGolang 异步和 CPU 使用率
【发布时间】:2018-09-25 12:57:48
【问题描述】:

我正在学习 Go 并发,我的期望是使用 goroutines 和通道应该增加并发性。该程序需要几毫秒才能完成。但是随着负载的增加,尽管有大量的 CPU 空闲,但执行时间会不断增加。

我正在向下面的程序发送 1200 QPS/TPS 以分析请求到响应的时间,我发现程序的整体执行时间随着时间的推移而增加。此外,CPU 使用率约为 3-6%。

当我将 QPS 增加到 100,000 时,程序的执行时间增加到秒(从最初的毫秒)。但 CPU 使用率保持在 8-9%。

那么为什么程序不使用其他 90-94% 的可用 CPU 并更快地完成程序的执行?

ulimit -n 是 2000000。

package main

import (
    "fmt"
    "github.com/valyala/fasthttp"
    "strings"
    "sync"
)

func total(in chan int, out chan int) {
    res := 0
    for iter := range in {
        res += iter
    }
    out <- res // sends back the result
}

func check() {

    ch := make(chan int)
    rch := make(chan int)
    go total(ch, rch)
    ch <- 1
    ch <- 2
    ch <- 3
    close(ch)       // this will end the loop in the total function
    result := <-rch // waits for total to give the result
    fmt.Println("Total is ", result)
}

func main() {
    var wg sync.WaitGroup
    wg.Add(1)

    go func() {
        m := func(ctx *fasthttp.RequestCtx) {

            maingetpath := ctx.Path()
            urlPart := strings.Split(string(maingetpath), "/")
            func := urlPart[1]
            switch string(func) {
            case "white":
                check()
            default:
                ctx.Error("not found", fasthttp.StatusNotFound)
            }
        }

        fasthttp.ListenAndServe(":8080", m)
        defer wg.Done()
    }()

    wg.Wait()
}

【问题讨论】:

  • 这不能编译; m in main 未定义。此外,函数末尾的 defer 语句是多余的。将其放在顶部或附近,或移除延迟。在这种情况下,您根本不需要 main 中的匿名 goroutine。
  • 忽略关于 m 未定义的部分。我被你那古怪的缩进弄糊涂了。所以问题是为什么 main 中的 goroutine 不能让你的程序更快?因为添加它根本没有区别,这就是原因。您只是用匿名的 goroutine 替换了主 goroutine。 main 除了等待之外什么都不做。
  • 这个问题没有意义。
  • 那么 CPU 使用率如何......即使我在 main 中删除匿名 go.. 我仍然处于 3-6% CPU,并且随着 QPS 的增加,程序的执行时间也会增加。为什么 CPU 不能增加到 90% 并给我更好的执行时间来增加 QPS

标签: go concurrency cpu


【解决方案1】:

我不确定您在这个小服务器上到底想做什么。

1) 您正在创建一个 WaitGroup 并向其添加 1,调用匿名 go 例程,然后在 main 中等待,这将您的 main 移动到匿名函数中。

2) 让我们看看你在 checktotal 函数中做了什么:

func total(in chan int, out chan int) {
    res := 0
    // this will just pull the value, and then wait till the next value 
    // is pushed... till you close the "in" channel
    for iter := range in {
        res += iter
    }
    out <- res // sends back the result
}

func check() {

    ch := make(chan int)
    rch := make(chan int)
    go total(ch, rch)
    // we are pushing this value into a unbuffered channel...
    ch <- 1  // this gets pushed and waits until it is pulled in the total function 
    ch <- 2  // this gets pushed and waits until it is pulled in the total function 
    ch <- 3  // this gets pushed and waits until it is pulled in the total function 
    close(ch)       // this will end the loop in the total function
    result := <-rch // waits for total to give the result
    fmt.Println("Total is ", result)
} 

请帮助我了解当它完全同步时如何使用任何并发?

也许如果你在 go 例程中调用 check 会更有效率,但对我来说仍然没有任何意义。

【讨论】:

  • 它是异步的,我在关注stackoverflow.com/questions/12398359/…
  • 再次声明,并没有使它更正确。 @Popmedic 是对的。虽然有一个 go 例程做一些工作,但例程的调用者只是阻塞。
猜你喜欢
  • 2018-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多