Ruby 多线程中的循环

Ruby 多线程中的循环,ruby,multithreading,ruby-1.9,Ruby,Multithreading,Ruby 1.9,我有以下代码(): 这是一个使用互斥体的示例。同步。在我的电脑上,结果与教程完全不同。调用join后,计数有时相等: count1 : 5321211 count2 : 6812638 difference : 0 count1 : 27307724 count2 : 27307724 difference : 0 有时不是: count1 : 4456390 count2 : 5981589 difference : 0 count1 : 25887977 count2 :

我有以下代码():

这是一个使用
互斥体的示例。同步
。在我的电脑上,结果与教程完全不同。调用
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返回到线程时,它应该从中断的那一行继续,对吗

仍然只有一个线程正在写入变量。在
循环do
块中,
count2+=1
执行的次数怎么可能多得多

执行

puts "count1 :  #{count1}"
需要一些时间(虽然可能很短)。这不是在一个实例中完成的。因此,这两条连续的线并不神秘:

puts "count1 :  #{count1}"
puts "count2 :  #{count2}"
显示不同的计数。简单地说,
计数器
线程在执行第一个
put
时经历了一些循环周期并增加了计数

同样,当

difference += (count1 - count2).abs
计算后,在引用
count2
之前引用
count1
时,计数原则上可以增加。但是在这个时间跨度内没有执行任何命令,我猜引用
count1
所需的时间要比
计数器
线程通过另一个循环所需的时间短得多。请注意,在前者中执行的操作是在后者中执行的操作的适当子集。如果差异足够显著,这意味着
计数器
线程在
-
方法的参数调用期间没有经历循环周期,那么
count1
count2
将显示为相同的值

一个预测是,如果您在引用
count1
之后但在引用
count2
之前进行了一些昂贵的计算,那么
差异将显示:

difference += (count1.tap{some_expensive_calculation} - count2).abs
# => larger `difference`

答案是这样的。我认为您假设线程在
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中,当主线程执行时,线程似乎没有机会运行

本教程可能是为ruby 1.8编写的,但是线程模型在1.9中已经更改


事实上,它在1.8中工作纯属“幸运”,因为当
join(2)
在1.8和1.9中都没有返回时,线程不会完成执行

join(2)
应该做什么?它给线程一个终止的限制(以秒为单位)。如果我不调用它,ruby将在到达程序末尾时自动收获线程(因此无限
循环do
将始终结束)。有关更多有趣的信息,请参阅。在ruby 1.8上,
difference
始终为0,计数之间的差异不会超过1,但在ruby 1.9上,
difference
始终为==0,但count1和count2彼此相差很远。事实上,在计数器线程中放置类似于
sleep 0.001
的内容也会使差异显示出来。由于计数器线程是“忙循环”,我想知道间谍线程是否有很多机会在1.9中运行。将sleep语句立即释放CPU时间来运行spy线程,差别就显现出来了。谢谢,这很有意义。将
put
替换为
print“count1:#{count1},count2:#{count2}\n”
可以减少计数器之间的差异。因为
put
作为两个命令执行,因此需要更多的时间。
...
counter.join(2)
spy.join(2)

counter.kill
spy.kill

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