多个线程中的循环

时间:2012-10-25 07:58:27

标签: ruby multithreading ruby-1.9

我有以下代码(from a Ruby tutorial):

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返回到线程时,它应该从它被中断的行继续,对吧?

还有一个线程正在写入变量。如何在loop do块中count2 += 1执行更多次?

2 个答案:

答案 0 :(得分:3)

执行

puts "count1 :  #{count1}"

需要一些时间(尽管可能很短)。它不是在一个实例中完成的。因此,连续两行并不神秘:

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

显示不同的计数。简单地说,counter线程经历了一些循环周期,并在执行第一个puts时增加了计数。

同样,

difference += (count1 - count2).abs
计算

,在引用count1之前引用count2时,计数原则上可以递增。但是在该时间跨度内没有执行命令,我猜测引用count1所花费的时间比counter线程通过另一个循环所花费的时间要短得多。请注意,前者中的操作是后者中所做操作的适当子集。如果差异足够大,这意味着counter线程在-方法的参数调用期间没有经历循环周期,那么将出现count1count2同样的价值。

如果您在引用count1之后但在引用count2之前进行了一些昂贵的计算,则会出现预测:{/ 1}}将显示:

difference

答案 1 :(得分: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中进行了更改。

实际上它在1.8中工作是纯粹的“运气”,因为当join(2)在1.8和1.9中都没有返回时,线程没有完成执行。