Ruby线程将控制传递给main

时间:2010-10-29 10:05:41

标签: ruby multithreading

我正在使用Ruby编写应用程序,为每个新作业创建一个新线程。所以这就像一个队列管理器,我在那里检查可以从数据库启动多少个线程。现在当一个线程完成时,我想调用该方法来启动一个新的工作(即一个新的线程)。我不想创建嵌套线程,所以有没有办法加入/终止/退出调用线程并将控制传递给主线程?为了使情况清楚,此时可能会有其他线程运行。

我尝试简单地加入调用线程,如果它不是主线程,我得到以下错误;

"thread 0x7f8cf8dcf438 tried to join itself"

任何建议都将受到高度赞赏。

提前致谢。

2 个答案:

答案 0 :(得分:0)

我建议两个解决方案:

第一个有效地加入一个线程,但必须从主线程调用join(假设你从main开始所有的工作线程):

def thread_proc(s)
  sleep rand(5)
  puts "#{Thread.current.inspect}: #{s}"
end

strings = ["word", "test", "again", "value", "fox", "car"]

threads = []
2.times { 
  threads << Thread.new(strings.shift) { |s| thread_proc(s) }
}

while !threads.empty?
  threads.each { |t|
    t.join
    threads << Thread.new(strings.shift) { |s| thread_proc(s) } unless strings.empty?
    threads.delete(t)
  }
end

但该方法效率低下,因为反复创建线程会导致内存和CPU开销。

您应该通过使用队列来更好地同步固定的重用线程池:

require 'thread'

strings = ["word", "test", "again", "value", "fox", "car"]

q = Queue.new
strings.each { |s| q << s }

threads = []
2.times { threads << Thread.new {
  while !q.empty?
    s = q.pop
    sleep(rand(5))
    puts "#{Thread.current.inspect}: #{s}"
  end
}}

threads.each { |t| t.join }

答案 1 :(得分:0)

t1 = Thread.new { Thread.current[:status] = "1"; sleep 10; Thread.pass; sleep 100 }  
t2 = Thread.new { Thread.current[:status] = "2"; sleep 1000 }  
t3 = Thread.new { Thread.current[:status] = "3"; sleep 1000 }  

puts Thread.list.map {|X| x[:status] }
#=> 1,2,3

Thread.list.each do |x| 
  if x[:status] == 2 
    x.kill # kill the thread
    break
  end
end  

puts Thread.list.map {|X| x[:status] }
#=> 1,3

“Thread :: pass”会将控制传递给调度程序,调度程序现在可以调度任何其他线程。线程已自愿放弃对调度程序的控制 - 我们无法指定将控制权传递给特定线程

“Thread#kill”会杀死线程

的实例

“Thread :: list”将返回线程列表

线程由调度程序管理,如果您想要显式控制,则检查光纤。但它有一些问题,JRuby不支持光纤。

还检查线程局部变量,它将帮助您传达线程的状态或返回值,而无需加入线程。

http://github.com/defunkt/resque是队列的一个很好的选择,请查看它。如果你要大量使用线程,也可以试试JRuby。它的优点是它可以将java线程包装在ruby中。