我可以无痛地使用多少个goroutine?例如,维基百科说,在Erlang中,可以创建2000万个进程,而不会降低性能。
更新: 我刚刚对goroutine的性能进行了一些调查,并得到了这样的结果:
如果goroutine被阻止,则除以下内容外不涉及其他任何费用:
成本(就内存和实际开始执行goroutine的平均时间而言)为:
Go 1.6.2 (April 2016) 32-bit x86 CPU (A10-7850K 4GHz) | Number of goroutines: 100000 | Per goroutine: | Memory: 4536.84 bytes | Time: 1.634248 µs 64-bit x86 CPU (A10-7850K 4GHz) | Number of goroutines: 100000 | Per goroutine: | Memory: 4707.92 bytes | Time: 1.842097 µs Go release.r60.3 (December 2011) 32-bit x86 CPU (1.6 GHz) | Number of goroutines: 100000 | Per goroutine: | Memory: 4243.45 bytes | Time: 5.815950 µs
在装有4 GB内存的计算机上,这会将goroutine的最大数量限制为略少于一百万。
源代码(如果您已经理解上面打印的数字,则无需阅读此书):
package main import ( "flag" "fmt" "os" "runtime" "time" ) var n = flag.Int("n", 1e5, "Number of goroutines to create") var ch = make(chan byte) var counter = 0 func f() { counter++ <-ch // Block this goroutine } func main() { flag.Parse() if *n <= 0 { fmt.Fprintf(os.Stderr, "invalid number of goroutines") os.Exit(1) } // Limit the number of spare OS threads to just 1 runtime.GOMAXPROCS(1) // Make a copy of MemStats var m0 runtime.MemStats runtime.ReadMemStats(&m0) t0 := time.Now().UnixNano() for i := 0; i < *n; i++ { go f() } runtime.Gosched() t1 := time.Now().UnixNano() runtime.GC() // Make a copy of MemStats var m1 runtime.MemStats runtime.ReadMemStats(&m1) if counter != *n { fmt.Fprintf(os.Stderr, "failed to begin execution of all goroutines") os.Exit(1) } fmt.Printf("Number of goroutines: %d\n", *n) fmt.Printf("Per goroutine:\n") fmt.Printf(" Memory: %.2f bytes\n", float64(m1.Sys-m0.Sys)/float64(*n)) fmt.Printf(" Time: %f µs\n", float64(t1-t0)/float64(*n)/1e3) }