首先做这种运算实体并没有并行但想看看并行性能的benchmark, 请使用 testing package 的 benchmark framework, 能避免很多类似下面的坑。

坑:

go Proc0(NewG())

会比

go func() {
  Proc0(NewG())
}()

慢很多。因为

  1. NewG() 是在 calling goroutine 里执行的(spec明确说明了),你所有 goroutine 用的内存都是在同一个 goroutine 里分配。
  2. Memory allocator 有 thread cache, 同一个 goroutine 连续分配的小内存通常会分配到相邻空间(尤其是程序刚启动没什么碎片),这是基本的局部性假设。
  3. NewG() 分配的内存特别小,所以连续分配的话基本都在同一个 4K 页上,这个可以把NewG()的地址指针们的地址打出来验证。
  4. 好啦,开始并行跑了,你的 4 个 CPU cores 就开始抢着要cache这片内存,然后频繁写,频繁冲突失效,互相伤害,严重影响cache命中率,吞吐自然就没法scale了。