0
考虑以下应用程序,旨在衡量goroutine
创建延迟。假设我们正在运行GOMAXPROCS=2
。为什么会导致goroutine创建时间的差异?
package main
import "fmt"
import "time"
const numRuns = 10000
type timeRecord struct{
Ts time.Time
Msg string
}
var timeStamps []timeRecord
func threadMain(done chan bool) {
timeStamps = append(timeStamps, timeRecord{time.Now(), "Inside thread"})
done <- true
}
func main() {
timeStamps = make([]timeRecord, 0, numRuns*2)
done := make(chan bool)
dummy := 0
for i := 0; i < numRuns; i++ {
timeStamps = append(timeStamps, timeRecord{time.Now(), "Before creation"})
go threadMain(done)
<-done
}
// Regularize
regularizedTime := make([]time.Duration, numRuns*2)
for i := 0; i < len(timeStamps) ; i++ {
regularizedTime[i] = timeStamps[i].Ts.Sub(timeStamps[0].Ts)
}
// Fake timetraced
fmt.Printf("%6d ns (+%6d ns): %s\n", 0, 0, timeStamps[0].Msg)
for i := 1; i < len(timeStamps) ; i++ {
fmt.Printf("%8d ns (+%6d ns): %s\n", regularizedTime[i], (regularizedTime[i] - regularizedTime[i-1]).Nanoseconds(), timeStamps[i].Msg)
}
}
我的服务器上,这大致一致的中位数260 ns的增量输出从Before creation
到Inside thread
。现在考虑主要方法的以下变化。
timeStamps = make([]timeRecord, 0, numRuns*2)
done := make(chan bool)
dummy := 0
for i := 0; i < numRuns; i++ {
timeStamps = append(timeStamps, timeRecord{time.Now(), "Before creation"})
go threadMain(done)
for j := 0; j < 1000; j++ {
dummy += j
}
<-done
}
在这种变化中,在同一时间增量需要大约890 纳秒。
显然,确切的数字是机器的具体数字,但数字之间的差异是好奇的。从逻辑上讲,如果我在“创建之前”和“内部线程”之间测量,在go
声明之后添加额外的逻辑似乎不应该增加这个时间,但它确实如此。
有没有人有一个好主意,为什么时间增加没有发生在预期的位置?
因为'GOMAXPROCS = 2',我期待第二个goroutine可以真正的并行运行。 – merlin2011
第二个goroutine可以以真正的并行运行,但当前的Go运行时只能在某些安全点进行安排。尝试在'go threadMain(done)'之后添加'runtime.Gosched()'以强制它在for循环之前进行调度。当然,在这种情况下,go sceduler可能会在运行线程之间进行次优分配。如果你有一个真正的程序执行不好,因为它试图填写一个错误报告。 – kostya