gpt4 book ai didi

ruby - 拯救线程内部引发的同时错误

转载 作者:数据小太阳 更新时间:2023-10-29 07:37:24 25 4
gpt4 key购买 nike

使用以下脚本

threads = [
Thread.new { Thread.current.abort_on_exception = true; raise 'err' },
Thread.new { Thread.current.abort_on_exception = true; raise 'err' },
]

begin
threads.each(&:join)
rescue RuntimeError
puts "Got Error"
end

一半时间我得到预期的“Got Error”,导出为 0,另一半时间我得到 test.rb:3:in block in <main>': err (RuntimeError) .

rescue 不应该能够处理这个吗?如果不是,两个线程同时引发错误的替代解决方案可能是什么?

我考虑过不使用 abort_on_exception = true但问题是,如果第一个线程有,比如说 sleep(10)raise 之前,第二个线程会立即出错,直到 10 秒后才会被捕获(由于 threads 数组的顺序)。

Ruby MRI 版本: ruby 2.4.0p0(2016-12-24 修订版 57164)[x86_64-darwin15]

任何想法将不胜感激。谢谢!

更新

jruby-9.1.6.0好像没有这个问题。可能是因为它固有的线程安全性。它总是打印 Got Error无一异常(exception)。不幸的是,JRuby 不适合我们。

最佳答案

这里有一些拼图。


首先,程序只等待主线程完成:

Thread.new { Thread.current.abort_on_exception = true; raise 'Oh, no!' }

puts 'Ready or not, here I come'

以上可能会或可能不会引发错误。


其次,如果您加入一个线程,则该线程引发的异常会被加入的线程从 #join 方法中重新引发:

gollum = Thread.new { raise 'My precious!!!' }

begin
gollum.join
rescue => e
# Prints 'My precious!!!'
puts e.message
end

此时,执行返回到加入的线程。它不再连接到导致错误的线程或任何其他线程。它没有加入其他线程的原因是因为您一次只能加入一个线程。 threads.each(&:join) 实际上将您加入到第一个,当它结束时 - 到第二个等等:

frodo = Thread.new { raise 'Oh, no, Frodo!' }
sam = Thread.new { raise 'Oh, no, Sam!' }

begin
[frodo, sam].each(&:join)
rescue => e
puts e.message
end

puts 'This is the end, my only friend, the end.'

上面的打印

Oh, no, Frodo!
This is the end, my only friend, the end.


现在让我们把它放在一起:

frodo = Thread.new { Thread.current.abort_on_exception = true; raise 'Oh, no, Frodo!' }
sam = Thread.new { Thread.current.abort_on_exception = true; raise 'Oh, no, Sam!' }

begin
[frodo, sam].each(&:join)
rescue => e
puts e.message
end

puts 'This is the end, my only friend, the end.'

这里可以发生很多事情。重要的是,如果我们设法加入(在此之前我们没有收到错误),救援将在主线程中从首先设法引发异常的线程中捕获异常,然后在救援之后继续。之后,主线程(以及程序)可能会或可能不会在另一个线程引发其异常之前完成。


让我们检查一些可能的输出:

ex.rb:1:in `block in ': Oh, no, Frodo! (RuntimeError)

Frodo 在我们加入之前提出了他的异常(exception)。

Oh, no, Sam!
This is the end, my only friend, the end.

我们加入后,Sam 是第一个提出错误的人。我们在主线程打印错误信息后,也打印了结束。然后主线程结束,在 Frodo 可以提出他的错误之前。

Oh, no, Frodo!ex.rb:2:in `block in ': Oh, no, Sam! (RuntimeError)

我们成功加入了。佛罗多是第一个提出来的,我们营救并打印出来。山姆在我们可以打印结束之前提出。

Oh, no, Sam!
This is the end, my only friend, the end.ex.rb:1:in `block in ': Oh, no, Frodo! (RuntimeError)

(很少)我们设法营救了。 Sam 首先提出了一个错误,我们从主线程打印了它。我们打印了结尾。就在打印之后,但在主线程终止之前,Frodo 也设法指出了他的错误。


至于可能的解决方案,您只需要尽可能多的救援,因为可能会引发线程。请注意,我还将线程创建放在 protected block 中,以确保我们在连接之前也能捕获潜在的错误:

def execute_safely_concurrently(number_of_threads, &work)
return if number_of_threads.zero?

begin
Thread.new(&work).join
rescue => e
puts e
end

execute_safely_concurrently(number_of_threads.pred, &work)
end

execute_safely_concurrently(2) do
Thread.current.abort_on_exception = true
raise 'Handle me, bitte!'
end

关于ruby - 拯救线程内部引发的同时错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41736068/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com