Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby中的多线程(MRI)_Ruby_Multithreading - Fatal编程技术网

Ruby中的多线程(MRI)

Ruby中的多线程(MRI),ruby,multithreading,Ruby,Multithreading,根据Ruby(MRI)中的GIL实现,以下代码必须通过多次打印消息而失败。但事实并非如此,它总是打印一次: class Sheep def initialize @shorn = false end def shorn? @shorn end def shorn! puts "shearing..." @shorn = true end end s = Sheep.new 55.times.map do Thread.new {

根据Ruby(MRI)中的GIL实现,以下代码必须通过多次打印消息而失败。但事实并非如此,它总是打印一次:

class Sheep
  def initialize
    @shorn = false
  end

  def shorn?
    @shorn
  end

  def shorn!
    puts "shearing..."
    @shorn = true
  end
end

s = Sheep.new
55.times.map do
  Thread.new { s.shorn! unless s.shorn? }
end.each(&:join)
为什么

$ ruby --version
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]

这在一定程度上取决于您使用的确切ruby版本(它们调度线程的方式不同)。在我的系统上,这有点取决于整个系统负载和终端的速度,但在Ruby 2.0.00p481上,我得到1到55行输出,在Ruby 1.8.7上,我始终只得到一行

这里应该注意的是,Ruby 2.0和更高版本使用实际的OS线程(尽管仍然使用GIL),而Ruby 1.8使用内部绿色线程,并有自己的调度。旧的ruby版本很可能会对线程进行更细粒度的调度


在任何情况下,您都不应该依赖任何附带的线程调度行为。这不是任何记录的行为的一部分,随着Ruby的成熟,不同系统上的情况将发生变化。在使用线程时,您应该始终确保安全地使用共享数据结构。

我使用Ruby版本
Ruby 2.1.5p273
,我认为您稍微不同的Ruby版本应该会产生类似的结果

我每次运行程序都会得到不同的结果

我尝试启用单核和前核。我看不出有什么不同。它不是线程安全的,正如您所期望的那样

否则,我能想到的唯一答案是,您的程序太快/轻量级,因此解释器不会经常考虑线程切换

在这种情况下,我只有一个建议。这是一个技巧,你可以给解释器一个提示,也许她可以切换线程。您可以使用
sleep
功能

在您的示例中,我会将其放在
竞赛条件之前:

  def shorn!
    sleep 0.0001
    puts "shearing..."
    @shorn = true
  end
如果你想了解更多关于GIL的信息,我可以推荐杰西·斯托莱默

如果您想了解更多关于Ruby和并发性的信息,我可以推荐Dotan Nahum


我建议的技巧被提到了

正如其他人提到的,GIL的行为没有文档记录,完全依赖于实现。您不应该依赖于对其调度行为的任何期望

然而,更详细(也是更一般)的答案是,调度器在线程之间切换执行,以确保没有单个线程阻止进程。这个开关称为上下文开关,或者更具体地说是线程开关

当上下文切换发生时,当前线程的执行将暂停,另一个线程的执行将恢复。如果是一个全新的线程正在“恢复”,那么这意味着新线程的执行从头开始

在您的程序中,每个新线程都以

s.shorn?
除非s.shorn?
,否则其计算结果为
。此时,
@shorn==false
s.shorn?
的计算结果为false。然后线程运行:

s.shorn!
#shorn中的第一个命令是:

将“剪切…”
接下来会发生什么取决于线程调度程序:

  • 如果调度程序决定让当前线程继续执行,那么执行的下一个命令是
    @shorn=true
    。然后线程结束,调度程序启动下一个线程,
    ,除非s.shorn?
    的计算结果为true,线程停止。此行为在循环中重复,直到不再有线程
  • 如果调度程序决定切换到另一个线程,那么它将在
    @shorn=true
    之前暂停执行,并从一开始就开始运行与以前相同的代码。这意味着新线程启动时
    @shorn==false
    ,因此
    将再次执行“剪切…”
  • 如您所见,这完全取决于调度器何时决定执行上下文切换

    但是吉尔呢? GIL是MRI Ruby中被严重误解的一部分。有很多资源可以解释GIL是如何工作的,但是在本例中,您应该知道的最重要的一点是GIL不能保证每个线程都按顺序运行


    相反,GIL仅仅保证用C实现的大多数核心Ruby方法(例如,
    Array#Ruby 2.0使用操作系统线程的证据在哪里?我使用Ruby 2.0,但总是有一条打印出来的消息。即使它是本机操作系统线程,MRI Ruby也不能同时执行多个线程,是吗?确切地说,Ruby 2.0使用操作系统线程,但它仍然有它的GIL()这确保了一次只能运行一个线程。请注意,还有其他Ruby实现,最突出的是JRuby和Rubinius,它们提供了真正的并行性,即在没有GIL的情况下(在多CPU机箱上)并行运行多个线程的能力。至于“证明”Ruby 1.9及更新版本使用本机线程,请参阅Yehuda Katz的博客文章。