2017-02-04 114 views
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 creationInside 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声明之后添加额外的逻辑似乎不应该增加这个时间,但它确实如此。

有没有人有一个好主意,为什么时间增加没有发生在预期的位置?

回答

0

Go调度程序是合作的。它只能在程序的某些点上将当前的goroutine切换到另一个goroutine,例如函数调用,读取/写入通道等等。我期望您观察到的差异是由于goroutine在后面(后添加for循环)。

+0

因为'GOMAXPROCS = 2',我期待第二个goroutine可以真正的并行运行。 – merlin2011

+0

第二个goroutine可以以真正的并行运行,但当前的Go运行时只能在某些安全点进行安排。尝试在'go threadMain(done)'之后添加'runtime.Gosched()'以强制它在for循环之前进行调度。当然,在这种情况下,go sceduler可能会在运行线程之间进行次优分配。如果你有一个真正的程序执行不好,因为它试图填写一个错误报告。 – kostya

相关问题