2017-02-17 39 views
0

我有兩段代碼,桌面上有32個內核。爲什麼原子操作使用單獨的線程更快?

代碼A使用32個線程,並執行以下的事情,

1)將值寫入存儲器 2一些隨機位置)原子將值添加到全局變量。

代碼B使用16個線程向隨機位置寫入值,並使用另外16個線程自動將值添加到全局變量。

我想知道爲什麼代碼B在每秒對全局變量執行多少次原子操作方面速度更快。

這裏是碼A

var a uint64 = 0 

const N = 10 * 1024 * 1024 

var data [N]uint64 

func main() { 

    for i := 0; i < 32; i ++ { 
     go func(id int) { 
      source := rand.NewSource(int64(id)) 
      local_rand := rand.New(source) 
      for { 
       atomic.AddUint64(&a, uint64(1)) 
       data[local_rand.Int31n(N)] = uint64(1) 
      } 
     }(i) 

    } 

    var b uint64 = 0 

    for { 
     c := atomic.LoadUint64(&a) 

     fmt.Println(c - b) 
     b = c 
     time.Sleep(time.Second) 
    } 

} 

這裏是代碼B

var a uint64 = 0 

const N = 10 * 1024 * 1024 

var data [N]uint64 

func main() { 

    for i := 0; i < 16; i ++ { 
     go func(id int) { 
      source := rand.NewSource(int64(id)) 
      local_rand := rand.New(source) 
      for { 
       data[local_rand.Int31n(N)] = uint64(1) 
      } 
     }(i) 

    } 
    for i := 0; i < 16; i++ { 

     go func() { 
      for { 
       atomic.AddUint64(&a, uint64(1)) 
      } 

     }() 
    } 
    var b uint64 = 0 

    for { 
     c := atomic.LoadUint64(&a) 

     fmt.Println(c - b) 
     b = c 
     time.Sleep(time.Second) 
    } 

} 

回答

1

原子操作是昂貴的。爲了保持原子性,您需要確保該代碼塊互斥執行。通常這是通過使用像load-linked,store-conditional等指令來實現的。在你的代碼A中,你有32個原子操作,但在代碼B中,你只有16個。減少原子操作,減少執行時間!

作爲一個實驗,嘗試在代碼A中使用內存操作改變原子操作的順序。(先做內存,然後再原子化)。你應該看到執行時間的減少。

+0

我不認爲在代碼A中將線程數改爲16可以提高性能。 – luyi0619

+0

我沒有看到你提出的建議有什麼不同。記憶先是原子。我錯過了什麼嗎? – luyi0619

+0

如果您的所有線程都先執行原子操作,則它們都將爭奪鎖定。如果你首先有內存,他們都會首先執行內存,但是由於正在被緩存的內容,內存操作將在不同的時間完成。這意味着原子操作將在不同的時間開始。所以你不會有同樣的爭議。所以我期待更少的執行時間。可能你所有的數據都被緩存了,沒有按照我期望的那樣做。無論如何,這只是一種理論而已。 –

相關問題