【问题标题】:Asynchronous alarm signal异步报警信号
【发布时间】:2009-02-02 08:13:55
【问题描述】:

我正在寻找 Ruby 中 POSIX alarm(2)(或类似)的可移植接口。也就是说,我希望能够设置一个后台计时器,以便在 n 秒后向当前进程发送信号。

我在 ruby​​-talk 列表中找到了一些 2006 年的 good discussion,它提供了使用 dl/import 的解决方案,但这有点像 hack(尽管是一个简洁的 hack)并且不是很便携。

我查看了饱受诟病的Timeout 模块,虽然它在传统解释器中运行良好,但它在JRuby 下无法使用。我的程序是一个使用 Readline 库的小型命令行 shell:

TIMEOUT = 5 # seconds
loop do
  input = nil
  begin
    Timeout.timeout(TIMEOUT) do
      input = Readline::readline('> ', nil)
    end
  rescue Timeout::Error
    puts "Timeout"
    next
  end
  # do something with input
end

在 JRuby 下,readline 调用中的进程似乎阻塞,Timeout::Error 仅在 (a) 计时器到期和 (b) 用户输入新行之后才被抛出。并且异常没有得到拯救。嗯。

所以我想出了这个解决方法:

require 'readline'
class TimeoutException < Exception ; end
TIMEOUT = 5 # seconds

loop do
  input = nil
  start_time = Time.now
  thread = Thread.new { input = Readline::readline('> ', nil) }
  begin
    while thread.alive? do
      sleep(1) # prevent CPU from melting
      raise TimeoutException if(Time.now - start_time > TIMEOUT)
    end
  rescue TimeoutException
    thread.exit
    puts "Timeout"
  end
  # do something with input
end

这是...笨重(让我们有礼貌)。我只想要alarm(2)!我真的不想为此拖入非核心库(例如终结者)。有没有更好的办法?

编辑: 我也找不到另一种选择——创建一个休眠的线程,然后向进程发送信号——也可以在 JRuby 下工作。 JRuby 吃信号吗?示例:

SIG = 'USR2'
Signal.trap(SIG) { raise }
Process.kill(SIG, Process.pid)

JRuby 简单地返回,Ruby 返回预期的“未处理异常”错误。

【问题讨论】:

    标签: ruby jruby


    【解决方案1】:

    很抱歉,对于您在 X 秒后向进程发送信号的更大问题,我没有答案,但您似乎只想在 X 秒等待输入后超时,并且如果是这种情况,那么我会说您正在寻找 Kernel.select :D

    我个人从未使用过这个,但是在为“非阻塞获取”做了一个 google 之后,并随后探索了链接,我发现这两个是非常宝贵的讨论:

    http://www.ruby-forum.com/topic/126795(多线程gets的讨论)

    http://www.ruby-forum.com/topic/121404(第二篇文章中对 Kernel.select 的解释)

    这里是如何使用它的示例。这将打印出您的提示并等待输入...如果五秒钟后没有输入,则程序将结束。如果有输入,一旦有输入,它就会将其吐出并结束……显然,您可以根据自己的目的进行修改。

    def prompt
      STDOUT.write "> "
      STDOUT.flush
    end
    
    def amusing_messages
      [ "You must enter something!", 
        "Why did you even start me if you just wanted to stare at me?", 
        "Isn't there anything better you could be doing?", 
        "Just terminate me already... this is getting old",
        "I'm waiting..."]
    end
    
    prompt
    
    loop do
      read_array, write_array, error_array = Kernel.select [STDIN], nil, nil, 5
    
      if read_array.nil?
        puts amusing_messages[rand(amusing_messages.length)]
      else
        puts "Result is: #{read_array[0].read_nonblock(30)}" 
      end
    
      prompt 
    
    end
    

    它可能不像你想的那么优雅,但它绝对可以完成工作,而无需处理线程。不幸的是,如果您想要更健壮的东西(定时器/向进程发送信号),这对您没有帮助,遗憾的是,我不知道这是否适用于 JRuby。很想知道它是否确实如此:)

    【讨论】:

    • +1 表示简洁,但我想保留 readline(命令行编辑、历史记录、完成......)。我已经重写了我的一个类,所以我可以放弃 JRuby。使用 BouncyCastle 进行快速原型制作很棒,但 JRuby 对于严肃的工作似乎还很年轻(不要跟我谈论 Kernel#select docs !!)。干杯!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多