我有这个脚本,上传一些文件,通过ssh连接并在远程服务器上做一些东西,有点像部署脚本,我想让它在我想要的时候运行并且能够重置它在处理过程中。
def deploy
# some stuff happens here
end
def do_deploy
$deploy.kill! if $deploy
$deploy = Thread.new { deploy }
$deploy.join # when I don't have the join here, it stop executing the deploy
# like after first when thread switches to something else, and
# then never finishes
end
reading = Thread.new do
while line = gets.chomp!
case line
when "q" then
puts "exiting"
Thread.exit
exit
when "r" then
do_deploy
end
end
end
reading.join
即使$deploy.join
使整个部署线程执行,它也会阻止读取任何输入,因此我无法在执行过程中重置它。我不能在剧本的最后加入它。
我基本上需要做的是在侦听输入时运行任务,并且能够终止进程并在任何给定时间重新启动它。或者甚至更好,发送一条可以立即处理的消息,例如关闭测试执行。
我知道杀死线程并不是一件好事,但在这种情况下,我认为这不是一个大问题。
我还想指出,我正在使用Windows,因此我没有fork()
可用。
有没有其他方法可以在没有线程的情况下解决这个问题?
编辑:刚刚发现,调用gets
会阻止所有其他线程执行,直到给出任何输入。在这个例子中
t1 = Thread.new { 10.times { |i| puts i } }
t2 = Thread.new { puts gets }
t1.join
t2.join
t1不会被执行,直到我向gets
提供一些输入。它只是永远坐在那里。如何在不阻塞所有线程的情况下从输入中读取?
edit2:刚刚发现,这是Windows related issue
edit3:问题在JRuby或Ruby 1.9中消失了
答案 0 :(得分:0)
使用Thread.join
时,调用线程将阻塞,直到指定的线程终止。这就是您此时无法处理输入的原因(do_deploy
不再被执行)。
调用deploy
后,Thread.new
线程应该立即执行。如果我正确地阅读了您的代码,您希望将来自.join
内部的do_deploy
移至reading
阻止内部。尝试使用以下reading
块(我没有在我面前使用Ruby,所以这可能不是完美的语法):
reading = Thread.new do
while line = gets.chomp!
case line
when "q" then
puts "exiting"
$deploy.kill if $deploy
break
when "r" then
do_deploy
end
end
$deploy.join
end
当输入“r”时,这应该启动(或杀死并重新启动)deploy
进程,然后返回到输入处理循环。输入“q”,deploy
进程将发送“终止”信号,输入处理循环将等待它终止,然后终止。
使用Ruby线程,当deploy
线程正在工作时(繁忙的线程可能会使低优先级线程饿死),输入处理线程似乎没有运行时,可能会遇到麻烦。如果您遇到这种情况,我建议您在Thread.pass
例程中向deploy
添加一些显式调用。这将强制线程调度程序让另一个线程运行。您可能还想尝试使用线程优先级并将输入处理线程置于比工作线程更高的优先级。
答案 1 :(得分:-1)
使用JRuby。它有真正的线程,不会成为C Ruby解释器所拥有的GIL(全局解释器锁)的牺牲品。