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}"