我正在使用Ruby编写应用程序,为每个新作业创建一个新线程。所以这就像一个队列管理器,我在那里检查可以从数据库启动多少个线程。现在当一个线程完成时,我想调用该方法来启动一个新的工作(即一个新的线程)。我不想创建嵌套线程,所以有没有办法加入/终止/退出调用线程并将控制传递给主线程?为了使情况清楚,此时可能会有其他线程运行。
我尝试简单地加入调用线程,如果它不是主线程,我得到以下错误;
"thread 0x7f8cf8dcf438 tried to join itself"
任何建议都将受到高度赞赏。
提前致谢。
答案 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中。