2013-07-20 33 views

回答

8

array是你的程序變量,當你應用像<<這樣的操作。它發生在三個步驟中:

  • 該變量首先被複制到CPU寄存器中。
  • CPU執行計算。
  • CPU將結果寫回變量存儲器。

所以這個高級單操作分三步進行。在這些步驟之間,由於線程上下文切換,其他線程可能會讀取變量的相同(舊)值。這就是爲什麼它不是原子操作。

+1

您可能會喜歡閱讀:[** Ruby原子操作**](http://moonbase.rydia.net/mental/blog/programming/atomic-operations-in-ruby.html) –

+1

你讀過了嗎?這個? [更新於Jörg's 2011年9月的評論](http://stackoverflow.com/questions/56087/does-ruby-have-real-multithreading/57802#57802) –

+0

@theTinMan非常感謝!我的英語很差:(但我注意到你的和以前的編輯到我的答案,我會改善下一個答案。謝謝! –

1

由於Ruby是一個非常高層次的語言,什麼都不是在操作系統級別真正原子化。只有非常簡單的彙編操作在操作系統級別是原子操作(取決於操作系統),每個Ruby操作(即使是簡單的操作)都對應於數百或數千個執行的彙編指令,例如方法查找,垃圾收集,對象初始化,範圍計算等。

如果您需要使操作原子化,請使用互斥鎖。

6

如果您有多個線程訪問同一個陣列,請使用Ruby的內置Queue類。它很好地處理生產者和消費者。

這是從文檔的例子:

require 'thread' 

queue = Queue.new 

producer = Thread.new do 
    5.times do |i| 
    sleep rand(i) # simulate expense 
    queue << i 
    puts "#{i} produced" 
    end 
end 

consumer = Thread.new do 
    5.times do |i| 
    value = queue.pop 
    sleep rand(i/2) # simulate expense 
    puts "consumed #{value}" 
    end 
end 

consumer.join 
5

實際使用MRI(馬茨的Ruby實現)的GIL(全局解釋器鎖)作出任何純C函數的原子。

由於Array#<<在MRI中被實現爲純C代碼,因此該操作將是原子操作。但請注意,這僅適用於MRI。在JRuby上,情況並非如此。

要完全瞭解正在發生的事情,我建議你閱讀這兩篇文章,這說明了一切非常好:

Nobody Understands the GIL
Nobody Understands the GIL - part 2

0

就riffing關閉@Linuxios和@TheTinMan的:高層語言(HLL)操作通常不是原子的。原子性(通常)不是單線程程序中的問題。在多線程程序中,你(程序員)必須以比單個HLL操作更高的粒度來推理它,因此單獨的HLL操作實際上對你沒有多大幫助。另一方面,儘管至少在現代硬件—之前和之後使得HLL操作原子只需要幾條機器指令,但靜態(二進制大小)和動態(執行時間)開銷相加。更糟的是,顯式原子性幾乎禁用了所有優化,因爲編譯器無法在原子操作之間移動指令。沒有真正的收益+顯着的成本=非首發。

相關問題