【问题标题】:Ruby Timeout.timeout does not timeout in x secsRuby Timeout.timeout 在 x 秒内不会超时
【发布时间】:2022-11-29 18:17:45
【问题描述】:

下面的代码

Timeout.timeout(2) do
  i = 0
  while(true)
    i = i + 1
    p "test #{i}"
  end
end

不会在 2 秒内超时。而低于类似代码的超时时间为 2 秒

Timeout.timeout(2) do
  i = 0
  while(true)
    i = i + 1
    # p "test #{i}"
  end
end

根本的区别是什么?请帮忙。

【问题讨论】:

  • 似乎是 Ruby 2.x 的问题。该代码在 Ruby 1.9 和 Ruby 3 中都运行良好。(即它~2s 后终止)
  • 除了这个问题,Timeout::timeout 有点危险,因为它会在任意点中断您的代码,可能使您的系统处于未定义或易受攻击的状态。最好使用某种计时器,例如run = true 标志以及 Thread.start { sleep(2) ; run = false } 和一个简单的 while(run) 循环。这样,它保证在完成一个完整的循环周期后完成。

标签: ruby ruby-on-rails-3


【解决方案1】:

我不知道这里到底发生了什么,我怀疑了解底层 C 代码的人会给出完整的答案。我有一个头绪。 Matz Ruby Interpreter (MRI) 有一个全局线程锁,这意味着在任何给定时间实际上只能运行一个线程。线程的工作方式是当一个线程正在等待它休眠的资源时,这为另一个线程提供了运行的机会。

超时创建第二个线程,该线程将休眠 2 秒,然后在当前线程上引发异常以强制超时。我们保证此线程不会在 2 秒之前运行,但不能准确保证它会在 2 秒后运行,但通常是几毫秒左右,但有一些例外。

p 函数的独特之处在于它直接写入 std.out。这是 C 程序员可能会有所帮助的地方,但在我看来,它可能会使另一个线程资源匮乏,因为要抛出异常,第二个线程需要拥有 std.out。

ppp 都会导致此问题,而 puts 不会。

为了支持资源饥饿理论,以下代码有效

Timeout.timeout(2) do
  i = 0
  while(true)
    i = i + 1
    p "testing timeout #{i}"
    sleep 0.001
  end
end

【讨论】:

  • 奇怪的是:即使没有 sleepruby timeout_test.rb > out 也会超时。
猜你喜欢
  • 2011-04-11
  • 1970-01-01
  • 1970-01-01
  • 2016-08-17
  • 1970-01-01
  • 2021-01-03
  • 2011-01-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多