如何在Ruby中同时运行两个线程?

时间:2010-03-11 19:47:52

标签: ruby multithreading

有没有办法同时运行2个线程?

我想让我的应用程序运行其当前函数,然后启动另一个运行另一个函数的线程,它可以更改第一个线程中的变量。

4 个答案:

答案 0 :(得分:15)

如果要同时运行两个线程,整个执行堆栈必须能够执行此操作。让我们从顶部开始:

  1. Ruby本身能够同时运行两个线程,没问题。但是,Ruby只是一种编程语言,即只是一堆规则。为了运行您的程序,您需要一个Ruby 实现。不幸的是,许多流行的Ruby实现能够同时运行多个线程,包括MRI,YARV和Rubinius。事实上,只能生产就绪的Ruby实现可以同时运行线程是JRuby。 (IronRuby也是如此,但技术上还没有生产就绪,尽管最终的1.0版本可能只有几天了。)
  2. 但是JRuby(和IronRuby)实际上并没有自己实现线程,它们只是使用底层平台的线程。即JRuby将Ruby线程映射到JVM线程,IronRuby将它们映射到CLI线程。因此,底层平台也必须能够并行运行线程。
  3. 同样:JVM和CLI原则上都能够并行运行线程,但JVM和CLI只是规范,它们只是纸上谈兵。为了运行代码,您需要实现这些规范,而不是所有 支持真正的并发线程。
  4. 即使如果你的平台实现支持真正的并发线程,他们自己也可以将他们的线程实现委托给底层操作系统,就像JRuby委托给JVM一样。例如,.NET,Mono,HotSpot和JRockit(分别是CLI和JVM的最流行的实现)使用本机OS线程作为其平台线程。因此,显然,操作系统必须能够并行运行线程。而且:并非所有人都是。
  5. 当然,如果你只有一个CPU,那么操作系统中的所有并行性都无济于事。如果您希望同时运行两个线程,则需要两个CPU,两个内核或两个同时发生的硬件线程。

答案 1 :(得分:2)

http://ruby-doc.org/core/classes/Thread.html

x = 2
Thread.new do
    x = 3
end
x = 4

对于真正的并发性,需要超过2个核心或2个处理器 - 但如果实现是单线程的(例如MRI),它可能无效。

答案 2 :(得分:1)

首先,我要回答你的问题:

thread_1 = Thread.new do
    #do something here
end

thread_2 = Thread.new do
   #do something here
end

thread_1.join
thread_2.join(timeout_in_seconds)

Thread#join使主线程等到连接的线程完成。如果以秒为单位指定超时,Ruby将在达到超时后关闭该线程。

现在,事实上,使用Matz Ruby解释器(MRI)在ruby 1.8中没有真正的并发性,但是只有一个处理器没有真正的并发性。根据{{​​3}}:

  

但是,作为此运行时的一部分,解释器还实例化this page(或更亲切地称为GIL)的实例,这是我们缺乏并发性的罪魁祸首

阅读文章本身以获取更多信息。

MRI尝试使用所谓的Global Interpreter Lock欺骗你,这意味着Ruby解释器负责处理与线程有关的所有事情,而不是操作系统,其他类型的线程,真正并发的线程称为本机线程和Ruby 1.9通过YARV支持它们,但这并不意味着每个Ruby线程并行运行,因为YARV具有全局VM锁(全局解释器锁或GIL),因此并发性是ruby中的一个神话并且它将持续很长时间

答案 3 :(得分:0)

http://ruby-doc.org/core/classes/Thread.html
请记住,只有在JRuby线程中才真正并行(其他解释器实现GIL)。来自here

# mutexsyncex.rb  
require 'thread'  # For Mutex class in Ruby 1.8  

# A BankAccount has a name, a checking amount, and a savings amount  
class BankAccount  
  def initialize(name, checking, savings)  
    @name,@checking,@savings = name,checking,savings  
    @lock = Mutex.new  # For thread safety  
  end  

  # Lock account and transfer money from savings to checking  
  def transfer_from_savings(x)  
    @lock.synchronize {  
      @savings -= x  
      @checking += x  
    }  
  end  

  # Lock account and report current balances  
  def report  
    @lock.synchronize {  
      "#@name\nChecking: #@checking\nSavings: #@savings"  
    }  
  end  
end 

ba = BankAccount.new('me', 1, 400)

ba.transfer_from_savings(10);
puts ba.report