测试代码:
package main
import (
"fmt"
"runtime"
)
func main() {
done := make(chan struct{})
defer close(done)
// 创建初始数据源
numbers := generator(done)
var stages []chan int
stages = append(stages, numbers)
for {
m := runtime.MemStats{}
runtime.ReadMemStats(&m)
//if m.Alloc > uint64(runtime.NumCPU()*1*1024*1024) { // 8核 * 2mb
if m.Alloc > uint64(1024*1024) { //1mb
break
}
//这里,在创建了10万个goroutine后结束
//if runtime.NumGoroutine() > 1e5 {
// break
//}
newStage := createStage(done, stages[len(stages)-1], func(x int) int {
return x + 1
})
stages = append(stages, newStage)
fmt.Printf("已创建 %d 个处理阶段\n", len(stages))
fmt.Printf("已创建 %d 个goroutine, mem: %d\n", runtime.NumGoroutine(), m.Alloc)
}
// 从最后一个阶段读取结果
for i := 0; i < 10; i++ {
select {
case res, ok := <-stages[len(stages)-1]:
if !ok {
fmt.Println("cloased:", res)
} else {
fmt.Printf("结果: %d\n", res)
}
}
}
}
func generator(done chan struct{}) chan int {
out := make(chan int)
go func() {
defer close(out)
for i := 0; ; i++ {
select {
case out <- i:
case <-done:
return
}
}
}()
return out
}
// 创建一个处理阶段
func createStage(done chan struct{}, in chan int, fn func(int) int) chan int {
out := make(chan int)
go func() {
defer close(out)
for n := range in {
select {
case out <- fn(n):
case <-done:
return
}
}
}()
return out
}
结果输出:
...
已创建 1274 个goroutine, mem: 1047800
已创建 1274 个处理阶段
已创建 1275 个goroutine, mem: 1048392
结果: 1273
结果: 1274
结果: 1275
结果: 1276
结果: 1277
结果: 1278
结果: 1279
分析: 在堆内存1mb情况下,可以创建一千个以上的并发串联运行的goroutine pipeline
当把内存占用扩大到 100mb
if m.Alloc > uint64(1024*1024),测试结果显示,可以运行15万以上的pipeline stage:
已创建 157782 个处理阶段
已创建 157783 个goroutine, mem: 104856448
已创建 157783 个处理阶段
已创建 157784 个goroutine, mem: 104857040
结果: 157782
结果: 157783
结果: 157784
结果: 157785
结果: 157786
结果: 157787
结果: 157788
结果: 157789