处理Ruby线程中引发的异常

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#joinThread#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.abort_on_exception = true是一个全局设置,因此请注意,它可能会破坏应用程序中的其他代码,或者它依赖于期望默认行为的依赖项。我会选择`t.abort_on_exception = true`的方法,除非它是一个很小的脚本。 (2认同)

Jas*_*ing 5

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)

  • 投票,因为这只是代码,没有解释.需要评论,描述它的作用,原因,等等. (9认同)
  • 我不同意这两种评论。 (3认同)
  • 也不要重写ruby核心类。-1 (2认同)