5

次のコードがあります(Rubyチュートリアルから):

require 'thread'

count1 = count2 = 0
difference = 0
counter = Thread.new do
   loop do
      count1 += 1
      count2 += 1
   end
end
spy = Thread.new do
   loop do
      difference += (count1 - count2).abs
   end
end
sleep 1

puts "count1 :  #{count1}"
puts "count2 :  #{count2}"
puts "difference : #{difference}"
counter.join(2)
spy.join(2)
puts "count1 :  #{count1}"
puts "count2 :  #{count2}"
puts "difference : #{difference}"

の使用例ですMutex.synchronize。私のコンピューターでは、結果はチュートリアルとはかなり異なります。を呼び出した後join、カウントが等しい場合があります。

count1 :  5321211
count2 :  6812638
difference : 0
count1 :  27307724
count2 :  27307724
difference : 0

時にはそうではありません:

count1 :  4456390
count2 :  5981589
difference : 0
count1 :  25887977
count2 :  28204117
difference : 0

0カウントが非常に異なる数値を示しているにもかかわらず、違いがまだ残っている可能性があることを理解していません。

操作はおそらく次のaddようになります。

val = fetch_current(count1)
add 1 to val
store val back into count1

と似たようなものですcount2。Rubyはスレッド間で実行を切り替えることができるので、変数への書き込みが終わらないかもしれませんが、CPUがスレッドに戻ると、中断された行から続行するはずですよね?

そして、変数に書き込みを行っているスレッドはまだ 1 つだけです。loop doブロック内で、count2 += 1より多くの回数が実行される可能性はありますか?

4

2 に答える 2

3

実行

puts "count1 :  #{count1}"

時間がかかります(短いかもしれませんが)。インスタンスでは実行されません。したがって、次の 2 行が連続していることは不思議ではありません。

puts "count1 :  #{count1}"
puts "count2 :  #{count2}"

異なるカウントを示しています。簡単に言えば、counterスレッドはいくつかのループ サイクルを経て、最初のループputsが実行されている間にカウントをインクリメントしました。

同様に、

difference += (count1 - count2).abs

が計算されると、カウントは、原則として、count1が参照される前に参照されている間にインクリメントされcount2ます。しかし、その時間内に実行されたコマンドはなく、参照にかかる時間は、スレッドが別のループを通過するcount1のにかかる時間よりもはるかに短いと思います。counter前者で行われる操作は、後者で行われるものの適切なサブセットであることに注意してください。差が十分に大きい場合、つまりメソッドcounterの引数呼び出し中にスレッドがループ サイクルを通過していない場合、とは同じ値として表示されます。-count1count2

count1予測は、 を参照した後、 を参照する前に高価な計算を行うとcount2、次のdifferenceように表示されます。

difference += (count1.tap{some_expensive_calculation} - count2).abs
# => larger `difference`
于 2012-10-25T08:53:41.360 に答える
0

これが答えです。リターン後にスレッドが実行を停止すると仮定したと思いますjoin(2)

これはそうではありません!join(2)スレッドは、 (一時的に) 実行をメイン スレッドに戻しても実行を続けます。

コードをこれに変更すると、何が起こるかがわかります。

...
counter.join(2)
spy.join(2)

counter.kill
spy.kill

puts "count1 :  #{count1}"
puts "count2 :  #{count2}"
puts "difference : #{difference}"

これは、メイン スレッドの実行中にスレッドが実行される機会がないように見える ruby​​ 1.8 では、少し異なる動作をするようです。

チュートリアルはおそらく ruby​​ 1.8 用に書かれていますが、1.9 ではスレッド モデルが変更されています。

実際、join(2)1.8 でも 1.9 でも返されたときにスレッドが実行を終了しないため、1.8 で機能したのは純粋な「運」でした。

于 2012-10-25T09:02:52.637 に答える