panjf2000 / ants

🐜🐜🐜 ants is the most powerful and reliable pooling solution for Go.
https://ants.andypan.me/
MIT License
12.83k stars 1.36k forks source link

[Bug]: ants.NewPoolWithFunc(1000, dorequest),当dorequest函数中不使用fmt.Println时,CPU耗尽;当使用打印函数时,CPU正常 #268

Closed yingjie52 closed 1 year ago

yingjie52 commented 1 year ago

Actions I've taken before I'm here

What happened?

ants.NewPoolWithFunc(1000, dorequest): 当dorequest函数中不使用fmt.Println时,CPU耗尽; 当dorequest使用打印函数时,CPU在50%左右

Major version of ants

v2

Specific version of ants

v2.7.0

Operating system

Windows

Relevant log output

CPU耗尽

Code snippets (optional)

package main

import (
    "fmt"
    "github.com/panjf2000/ants/v2"
    "github.com/valyala/fasthttp"
    "runtime"
    "strconv"
    "sync"
    "time"
)

var (
    ok int // 成功次数
    no int // 失败次数
)
var mu = sync.RWMutex{} // 加锁

var tunnel = make(chan string, 20000)

var wg sync.WaitGroup

// 请求数量
func count() {
    for i := 0; i < 1000000; i++ {

        tunnel <- strconv.Itoa(i)
        wg.Add(1)
    }

}

// 处理请求
func dorequest(i interface{}) {

    _, _, err := fasthttp.Get(nil, "http://localhost:8081/")
    if err == nil {
        mu.Lock() // 上锁
        ok++
        mu.Unlock() // 解锁
    } else {
        mu.Lock() // 上锁
        no++
        mu.Unlock() // 解锁
    }
    fmt.Println(i)
    wg.Done()

}

func main() {
    //使用所有CPU核心
    runtime.GOMAXPROCS(runtime.NumCPU())

    go count()

    time.Sleep(1 * time.Millisecond)

    chairPool, _ := ants.NewPoolWithFunc(20000, dorequest) // 声明有几把电椅
    defer chairPool.Release()

    for {
        select {
        case a := <-tunnel:
            _ = chairPool.Invoke(a)

        default:
            wg.Wait()
            fmt.Println("所有请求已处理完毕")
            return
        }
    }

}

How to Reproduce

Steps to reproduce the behavior:

  1. Go to '....'
  2. Click on '....'
  3. Do '....'
  4. See '....' 3333

Does this issue reproduce with the latest release?

I haven't verified it with the latest release

yingjie52 commented 1 year ago

希望当不使用打印函数的时候,CPU正常

panjf2000 commented 1 year ago

你得 pprof 一下,看看是什么地方在耗 CPU。

yingjie52 commented 1 year ago

你得 pprof 一下,看看是什么地方在耗 CPU。

我使用你的例子,注释掉myFunc中的打印,CPU也是升高。详细代码发在DIscussion里面了。刚学习go, pprof不会用,我在看看

yingjie52 commented 1 year ago

你得 pprof 一下,看看是什么地方在耗 CPU。

var sum int32

func myFunc(i interface{}) { n := i.(int32) atomic.AddInt32(&sum, n) fmt.Printf("run with %d\n", n) }

func demoFunc() { time.Sleep(1 * time.Millisecond) //fmt.Println("Hello World!") }

func main() { defer ants.Release()

runTimes := 10000000

// Use the common pool. var wg sync.WaitGroup syncCalculateSum := func() { demoFunc() wg.Done() } for i := 0; i < runTimes; i++ { wg.Add(1) _ = ants.Submit(syncCalculateSum) } wg.Wait() fmt.Printf("running goroutines: %d\n", ants.Running()) fmt.Printf("finish all tasks.\n")

// Use the pool with a function, // set 10 to the capacity of goroutine pool and 1 second for expired duration. p, := ants.NewPoolWithFunc(1000, func(i interface{}) { myFunc(i) wg.Done() }) defer p.Release() // Submit tasks one by one. for i := 0; i < runTimes; i++ { wg.Add(1) = p.Invoke(int32(i)) } wg.Wait() fmt.Printf("running goroutines: %d\n", p.Running()) fmt.Printf("finish all tasks, result is %d\n", sum)

liangjfblue commented 1 year ago

@yingjie52 你这个是并发上来, 且都在抢同一锁导致的

panjf2000 commented 1 year ago

正如 @liangjfblue 所说,这里 CPU 飙升有很大可能是因为锁竞争,而且我看你的 HTTP 请求是直接访问 127.0.0.1,这样的话除非有特殊的路由配置否则这一类请求是不走网卡的,因此是非常快的,所以这里大概也没能给并发抢锁争取缓冲时间,所以导致了 CPU 飙高。

这个 issue 我先关闭了,如果不是这里所说的原因那么后面可以再打开,谢谢!