Aka*_*wal 32 ruby multithreading exception-handling
我正在寻找一个经典的异常处理问题的解决方案.请考虑以下代码:
def foo(n)
puts " for #{n}"
sleep n
raise "after #{n}"
end
begin
threads = []
[5, 15, 20, 3].each do |i|
threads << Thread.new do
foo(i)
end
end
threads.each(&:join)
rescue Exception => e
puts "EXCEPTION: #{e.inspect}"
puts "MESSAGE: #{e.message}"
end
Run Code Online (Sandbox Code Playgroud)
此代码在5秒后捕获异常.
但是如果我将数组更改为[15, 5, 20, 3]
,则上面的代码会在15秒后捕获异常.简而言之,它始终捕获第一个线程中引发的异常.
任何想法,为什么如此.为什么不在每次3秒后捕获异常?如何通过任何线程捕获第一个引发的异常?
Ali*_*kau 59
如果您希望任何线程中的任何未处理的异常导致解释器退出,则需要将Thread :: abort_on_exception =设置为true
.未处理的异常导致线程停止运行.如果未将此变量设置为true,则仅在调用Thread#join
或Thread#value
为线程时引发异常.如果设置为true,它将在它发生时被引发并传播到主线程.
Thread.abort_on_exception=true # add this
def foo(n)
puts " for #{n}"
sleep n
raise "after #{n}"
end
begin
threads = []
[15, 5, 20, 3].each do |i|
threads << Thread.new do
foo(i)
end
end
threads.each(&:join)
rescue Exception => e
puts "EXCEPTION: #{e.inspect}"
puts "MESSAGE: #{e.message}"
end
Run Code Online (Sandbox Code Playgroud)
输出:
for 5
for 20
for 3
for 15
EXCEPTION: #<RuntimeError: after 3>
MESSAGE: after 3
Run Code Online (Sandbox Code Playgroud)
注意:但如果您希望任何特定的线程实例以这种方式引发异常,则有类似的abort_on_exception = Thread实例方法:
t = Thread.new {
# do something and raise exception
}
t.abort_on_exception = true
Run Code Online (Sandbox Code Playgroud)
Thread.class_eval do
alias_method :initialize_without_exception_bubbling, :initialize
def initialize(*args, &block)
initialize_without_exception_bubbling(*args) {
begin
block.call
rescue Exception => e
Thread.main.raise e
end
}
end
end
Run Code Online (Sandbox Code Playgroud)