• panjf2000 浏览»

    就是要这么对比才合理:不池化 vs 池化,我项目里的 benchmark 代码里也有用 buffered channel 实现简单的池化,所以是:原生 go 程 vs 用 buffered channel 简单池化 vs 用 ants pool。只要是手动限制 go 程数量,本身已经是做池化了。

  • panjf2000 浏览»

    mutex 需要把等待锁的 goroutine 放置在等待队列,等到锁释放了才唤醒,使用 spin-lock 是利用 gosched 抢占调度主动让出 CPU 并且把当前 goroutine 保存堆栈状态,以 _Grunnable 状态放入 Global 队列中,无需对 G 进行唤醒操作,因为总会有 M 从 Global 队列取得并执行该 G,性能会稍有提升。
    另外,其实 mutex 内部也实现了 spin-lock,但是这个内置的 spin-lock 机制只会 spin 几次而已,而且还有其他的限制条件比如:GOMAXPROCS>1、多核、当前 G 所在的 P 的 local 队列为空,有兴趣可看下源码:https://github.com/golang/go/blob/97d0505334c71a8d7a1e7431c1e1515c93b59e2b/src/runtime/proc.go#L5321-L5334

  • smallbull 浏览»

    想请问下,V2 版本中 Replace mutex with spin-lock 是出于什么考虑?或者解释下原因

  • panjf2000 浏览»

    共勉 ~~

  • stupidjohn 浏览»

    func BenchmarkQueue(b *testing.B) {
    	var wg sync.WaitGroup
    	for i :=0; i<b.N; i++ {
    		runQ := Generate(100000)
    		wg.Add(RunTimes)
    		for j:=0; j<RunTimes; j++ {
    			runQ(func() {
    				demoFunc()
    				wg.Done()
    			})
    		}
    		wg.Wait()
    	}
    }
    

    这样测试就可以公平比较 go func 和池化的差距,我这边的测试数据显示池化确实能节省一部分内存,但是时间却增加了,看起来还有部分优化的空间

  • stupidjohn 浏览»

    之前看过 go runtime 的代码,newproc1 会使用一个 g pool 来重复利用 goroutine 的数据结构和栈空间,所以一直没有测试 go func 和额外池化的性能差距,今天看了博主的的文章后测试了一下,确认了池化确实能节省一些内存开销,不过博主的对比方案不是很科学,应该用限制了最大数量的 go func 来对比,类似

    func Generate(worker int64) func(f func()) {
    	var idle = worker
    	wait := make(chan struct{}, 1)
    	return func(f func()) {
    		if atomic.AddInt64(&idle, -1) < 0 {
    			<- wait
    		}
    		go func() {
    			f()
    			if atomic.AddInt64(&idle, 1) <=0 {
    				wait <- struct{}{}
    			}
    		}()
    	}
    }
    
  • Ww2Zero 浏览»

    👍 文章写得很好,看了《后会有期》,感觉文章很细腻,向大佬学习。❤️

  • kenzyyang 浏览»

    我来了!

  • panjf2000 浏览»

    哈哈,谢谢,小姐姐你也很可爱 ☺️