8

我正在用 Ruby 为我的工作编写一个作业调度应用程序(主要是使用各种协议以给定的频率移动文件)

我的主循环如下所示:

while true do
  # some code to launch the proper job
  sleep CONFIG["interval"]
end

它的工作就像一个魅力,但我不确定它是否足够安全,因为应用程序可能在运行 cpu 密集型软件的服务器上运行。

有没有其他方法可以做同样的事情,或者sleep()在我的情况下足够安全?

4

5 回答 5

7

每当我觉得需要阻塞时,我都会使用事件循环;通常是libev。这是一个 Ruby 绑定:

http://rev.rubyforge.org/rdoc/

基本上,sleep如果您希望您的进程进入睡眠状态而不在后台进行任何其他操作,那是完全可以的。但是,如果您想做其他事情,例如睡眠并等待 TCP 连接或文件句柄变得可读,那么您将不得不使用事件循环。那么,为什么不在一开始就使用一个呢?

您的申请流程将是:

main {
   Timer->new( after => 0, every => 60 seconds, run => { <do your work> } )
   loop();
}

当你想做其他事情时,你只需创建观察者,它就会发生在你身上。(您正在运行的作业也可以创建观察者。)

于 2009-07-24T18:26:52.450 回答
6

对于快速和肮脏的事情,使用 sleep 可能是可以的。但是对于需要更多鲁棒性或可靠性的事情,我建议睡眠是邪恶的:) 睡眠的问题是线程(我在这里假设 Windows ......)真的睡着了 - 调度程序不会运行线程直到睡眠间隔过去一段时间。

在此期间,线程不会因任何事情而唤醒。这意味着它不能被取消或唤醒以处理某种事件。当然,进程可以被杀死,但这并没有给睡眠线程一个唤醒和清理任何东西的机会。

我对 Ruby 不熟悉,但我认为它具有某种等待多种事物的功能。如果可以的话,我建议您不要使用睡眠,而是等待两件事\

  1. 定期唤醒线程以完成其工作的计时器。
  2. 当他的进程需要取消或完全取消时设置的事件(例如捕获 control-C)。

如果有某种事件可以用来表示需要工作,那就更好了。这将避免对计时器进行轮询。这通常会导致较低的资源利用率和响应速度更快的系统。

于 2009-07-24T18:38:57.307 回答
3

如果您不需要确切的间隔,那么这对我来说很有意义。如果您需要在没有漂移的情况下定期唤醒,您可能需要使用某种外部计时器。但是当你睡着时,你并没有使用 CPU 资源。昂贵的是任务切换。

于 2009-07-24T18:23:37.900 回答
3

虽然sleep(timeout)非常适合某些设计,但需要牢记一个重要的警告。

SA_RESTARTRuby 使用(参见此处)安装信号处理程序,这意味着您的sleep(或等效的select(nil, nil, nil, timeout))不能轻易被中断。您的信号处理程序将触发,但程序将立即返回到sleep. 如果您希望及时对 a 做出反应,这可能会带来不便SIGTERM

考虑到...

#! /usr/bin/ruby
Signal.trap("USR1") { puts "Hey, wake up!" }
Process.fork() { sleep 2 and Process.kill("USR1", Process.ppid) }
sleep 30
puts "Zzz.  I enjoyed my nap."

...执行大约需要 30 秒,而不是 2 秒。

作为一种解决方法,您可以改为在信号处理程序中抛出异常,这会中断上面的睡眠(或其他任何事情!)。您还可以切换到select基于 - 的循环并使用自管道技巧的变体在收到信号后“提前”唤醒。正如其他人所指出的,功能齐全的事件库也可用。

于 2009-07-24T19:44:07.863 回答
2

它在睡眠时不会使用 CPU,但如果你睡了很长时间,我会更担心正在运行的 ruby​​ 解释器在它没有做任何事情时会占用内存。这没什么大不了的。

于 2009-07-24T18:29:46.157 回答