锁定老帖子 主题:Ruby多线程
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-10-16
最后修改:2010-10-16
require 'monitor' class Counter attr_reader :count def initialize @count = 0 super end def tick3 @count += 1 end end class Counter2 < Monitor attr_reader :count def initialize @count = 0 super end def tick5 synchronize do @count += 1 end end end c = Counter.new t1 = Thread.new { 10000.times { c.tick3 } } t2 = Thread.new { 10000.times { c.tick3 } } t1.join t2.join puts c.count c = Counter2.new t1 = Thread.new { 10000.times { c.tick5 } } t2 = Thread.new { 10000.times { c.tick5 } } t1.join t2.join puts c.count 运行了很多次,输出的结果永远是: 13889 20000 本人刚学RUBY,请高手分析一下为何未同步的结果永远是13889,而不会有一点改变。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-10-18
放两天了,居然没有回复,看来得自己动手了,郁闷...
|
|
返回顶楼 | |
发表时间:2010-10-19
大概是因为你在用Ruby 1.8.x吧…?抱歉详细的分析暂时没空写,不过你可以试试换台机器用Ruby 1.8.x来跑会发现不同步的时候数字还是每次跑都一样。然后再试试用Ruby 1.9.x来看就会发现多数时候同步与否都一样了…
|
|
返回顶楼 | |
发表时间:2010-10-20
RednaxelaFX 写道 大概是因为你在用Ruby 1.8.x吧…?抱歉详细的分析暂时没空写,不过你可以试试换台机器用Ruby 1.8.x来跑会发现不同步的时候数字还是每次跑都一样。然后再试试用Ruby 1.9.x来看就会发现多数时候同步与否都一样了…
我用的是1.8.7 |
|
返回顶楼 | |
发表时间:2010-10-22
最后修改:2010-10-22
这是竞争条件的问题。
在两个线程抢先式运作(没有同步)的时候,第一个线程 x 执行到 += 内部(实际上是 先执行 Fixnum 的 `+' 方法,然后解释器进行 `=' 赋值)时,可能会出现刚好时间片到期的情况。此时线程调度器把执行权交给第二个线程 y,y 执行完一段时间的 @count 的递增,时间片到期,执行权回到 x。由于 x 的 += 之前已经进行到一半,要么是 `+' 的运算元刚作为实际参数传递进来,要么是 `+' 已经返回而解释器正要进行 `=' 赋值,而无论是哪种情况,它进行的运算都是“过期”了的。 第一种情况下,传递进来的参数(运算元)是上一次 x 执行时的 @count 的值,这时它会把这个过期的数值 +1 并返回给调用者,反而覆盖了 y 执行时递加的 @count 的值,丢失了那部分数据;第二种情况下,`+' 的返回值是上一次 x 执行时 (@count+1) 的值,而在 y 执行期间 @count 早已被递加数次了,线程 x 把 @count+1 赋给 @count,无疑也丢失了 y 执行时的 @count 数据。 同步之后,两个线程不再盲目抢先,每次必然要等队友 `+=' 结束后才执行,自然也就没有这个问题了。 |
|
返回顶楼 | |
发表时间:2010-10-22
苏小脉 写道 这是竞争条件的问题。
在两个线程抢先式运作(没有同步)的时候,第一个线程 x 执行到 += 内部(实际上是 先执行 Fixnum 的 `+' 方法,然后解释器进行 `=' 赋值)时,可能会出现刚好时间片到期的情况。此时线程调度器把执行权交给第二个线程 y,y 执行完一段时间的 @count 的递增,时间片到期,执行权回到 x。由于 x 的 += 之前已经进行到一半,要么是 `+' 的运算元刚作为实际参数传递进来,要么是 `+' 已经返回而解释器正要进行 `=' 赋值,而无论是哪种情况,它进行的运算都是“过期”了的。 第一种情况下,传递进来的参数(运算元)是上一次 x 执行时的 @count 的值,这时它会把这个过期的数值 +1 并返回给调用者,反而覆盖了 y 执行时递加的 @count 的值,丢失了那部分数据;第二种情况下,`+' 的返回值是上一次 x 执行时 (@count+1) 的值,而在 y 执行期间 @count 早已被递加数次了,线程 x 把 @count+1 赋给 @count,无疑也丢失了 y 执行时的 @count 数据。 同步之后,两个线程不再盲目抢先,每次必然要等队友 `+=' 结束后才执行,自然也就没有这个问题了。 首先谢谢你的回答,但可惜你答非所问,请再看一次问题,如果有空,再答一次 |
|
返回顶楼 | |
发表时间:2010-10-22
我运行的结果永远是20000,20000,ruby 1.9.2p0
|
|
返回顶楼 | |
发表时间:2010-10-23
最后修改:2010-10-23
Java.Eye管理員 写道 我运行的结果永远是20000,20000,ruby 1.9.2p0
RednaxelaFX 也说了1.9.x是这种结果,只是不知道Ruby的线程调度的细节是怎么的,如果1.9以后是这样的话,那同步是不是多余了?另外,rails最新版本是不是线程安全了,如果是,那么有哪些支持rails应用多线程的部署方案呢(假设应用本身也线程安全)?之前看过robbin关于rails应用的部署方案应该都是单线程运行的 |
|
返回顶楼 | |
发表时间:2010-10-23
最后修改:2010-10-23
Java.Eye管理員 写道 我运行的结果永远是20000,20000,ruby 1.9.2p0
你在楼主这段代码前面加一段: class Fixnum alias old_plus + def +(operand) 200.times {} old_plus(operand) end end 就会发现 Counter1 和 Counter2 的结果不同了。 |
|
返回顶楼 | |
发表时间:2010-10-24
RednaxelaFX 写道 大概是因为你在用Ruby 1.8.x吧…?抱歉详细的分析暂时没空写,不过你可以试试换台机器用Ruby 1.8.x来跑会发现不同步的时候数字还是每次跑都一样。然后再试试用Ruby 1.9.x来看就会发现多数时候同步与否都一样了…
这个应该是ruby vm对多线程调度的实现区别吧,高手同学有空分析一下?我对详细情况比较感兴趣 |
|
返回顶楼 | |