业务逻辑中超时的实现
TCP 连接等耗时操作都有timeout参数用来设置超时, 如果我们自己写一个计算也需要超时检查的话, 可以借助线程超时检查来完成.
对于 Thread, 当它被创建的时候就已经运行起来了, join
的作用是在主线程上等待它的完成.
join → thr
join(limit) → thr
1. 主线程挂起等待子线程运行完成.
2. 子线程不会退出, 直到达到时间限制.
3. 如果超时返回nil, 否则返回 `thr` .
4. 当主程序退出时, 会杀死所有没有 `join` 的线程.
5. If thr had previously raised an exception and the ::abort_on_exception or $DEBUG flags are not set, (so the exception has not yet been processed), it will be processed at this time.
DEMO one
# 用来接收结果
calc_result = nil
# 超级费时的处理
calc_thread = Thread.new do
sleep(2)
calc_result = 999
end
# 最多等待 500 ms
time_out = 0.500
if calc_thread.join(time_out).nil?
puts "expired"
else
puts calc_result
end
计算 fibonacci
thread.join(time_out)
可以看作为耗时操作, 最多等待 time_out
秒.
可以利用这个特点, 来实现 JavaScript 中 setInterval
的效果:
main.rb
def fibonacci(value)
return value if value.zero? || value == 1
fibonacci(value - 1) + fibonacci(value - 2)
end
def calc_fibonacci_with_timeout(value, time_out = nil)
result = nil
thread = Thread.new do
result = fibonacci(value)
end
if time_out.nil?
# 不限时
thread.join
else
true until (print '.'; thread.join(time_out))
end
result
end
num = ARGV.shift.to_i
num = 10 if num <= 0
num.times do |i|
value = i + 1
puts "fib(#{value}):\t\t #{calc_fibonacci_with_timeout(value, 0.1)}"
end
$ ruby main.rb 40
$ ruby main.rb 40
.fib(1): 1
.fib(2): 1
.fib(3): 2
.fib(4): 3
.fib(5): 5
.fib(6): 8
.fib(7): 13
.fib(8): 21
.fib(9): 34
.fib(10): 55
.fib(11): 89
.fib(12): 144
.fib(13): 233
.fib(14): 377
.fib(15): 610
.fib(16): 987
.fib(17): 1597
.fib(18): 2584
.fib(19): 4181
.fib(20): 6765
.fib(21): 10946
.fib(22): 17711
.fib(23): 28657
.fib(24): 46368
.fib(25): 75025
.fib(26): 121393
.fib(27): 196418
.fib(28): 317811
.fib(29): 514229
..fib(30): 832040
..fib(31): 1346269
...fib(32): 2178309
.....fib(33): 3524578
.......fib(34): 5702887
............fib(35): 9227465
.................fib(36): 14930352
...........................fib(37): 24157817
..........................................................fib(38): 39088169
...................................................................................fib(39): 63245986
..................................................................................................................................fib(40): 102334155
(每个点代表100ms的计算耗时)
使用 Timeout.timeout
标准库中提供了 timeout
, 也是用线程实现, 不过是借助 sleep .
require 'timeout'
result = nil
begin
Timeout.timeout(1) {
sleep 2
result = 999
}
rescue Timeout::Error => e
puts "timeout..."
end
puts "main. result:#{result}"