Ruby 编程/参考/对象/线程
Ruby 中的 Thread 类是一个包装器/帮助程序,用于操作线程(启动它们、检查状态、存储线程局部变量)。
这里是一个很好的教程。
请注意,对于 MRI 1.8,Ruby 使用“绿色线程”(伪线程 - 实际上是单线程)。对于 1.9,MRI 使用“带全局解释器锁的原生线程”,因此“通常是单线程的”。Jruby 使用真正的并发线程。IronRuby 使用真正的并发线程。Rubinius 目前与 MRI 1.9 类似。见这里以获得良好的背景。
因为 1.8 使用绿色线程,这意味着对于 Windows,任何“C”调用(如 gets、puts 等)都会阻塞所有其他线程,直到它返回。调度程序只能在运行 Ruby 代码时从一个线程切换到另一个线程。但是,您可以在一个线程中运行子进程,它将起作用,并且您可以运行 select,它仍然能够在线程之间切换。对于 Linux,这意味着您可以选择 $stdin,因此不会阻塞输入。但是,对于 Windows,您真的被卡住了。任何键盘输入都会阻塞所有其他线程。在 1.9 中,由于使用原生线程(执行 IO 调用的线程在 IO 调用返回之前释放对 GIL 的控制),这个问题不再那么严重。您可以使用 Jruby[1] 对于非阻塞 1.8。
在 1.9 中,您可以通过将 C 调用包装在 rb_thread_blocking_region 中来“绕过”全局线程锁(这将基本允许该线程“运行并完成其任务”,而其他 Ruby 线程仍然以一次一个的方式运行。当方法返回时,它将再次进入 Ruby 环境,并成为“全局锁定”(一次一个)线程之一)。
如果您想用一个特定于该线程的特定参数启动一个线程,您可以使用 Thread.current
Thread.new { puts Thread.current # unique! }
或者您可以用一个参数启动它,比如
th = Thread.new(33) {|parameter| thread_unique_parameter = parameter }
这避免了在启动线程时出现并发问题,例如
# BROKEN for x in [1,2,3] do Thread.new { puts x # probably always outputs 3 because x's value changes due to the outside scope } end
对于这种情况,使用 ThreadsWait 类。
require 'thwait' ThreadsWait.join_all(th1, th2, th3) do |th_that_just_exited| # could also call it like join_all([th1, th2, ...]) puts 'thread just exited', th_that_just_exited end # at this point they will all be done
请参阅Mutex 类了解如何控制线程之间的交互。