2017-02-04 119 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

相關問題