ruby:在提升中断之前完成循环迭代

时间:2017-06-26 11:56:42

标签: ruby loops exception error-handling interrupt

我循环了很多项目,我想定期中断循环以保存并在以后继续这样:

begin
  big_list.each do |i|
    # sensitive stuff
    sensitive_method(i)
    # other sensitive stuff
  end
rescue Interrupt
  # finish the current iteration
  # then do something else (save)
  # don't raise (print done)
end

敏感我的意思是,如果在迭代过程中引发Interrupt,数据将被破坏,所以我需要保证迭代在退出之前完成。

另外,如果引发了另一个异常,它仍然应该完成循环,但之后将其提升

编辑:

在测试场景中使用mudasobwa的答案:

while true
  result = begin
             puts "start"
             sleep 1
             puts "halfway"
             sleep 1
             puts "done\n\n"
              nil
            rescue Exception => e
              e
            end
  case result
    when Interrupt
      puts "STOPPED"
      break
    when Exception then raise result
  end
end

我明白了:

start
halfway
done

start
^C: /...
STOPPED

这是我的确切问题,我需要它来完成循环(睡眠,中途打印,睡眠,打印完成)然后才会爆发(包裹掉,睡觉......在方法中没有帮助)

3 个答案:

答案 0 :(得分:2)

TL; DR:无法从中间内部继续执行该方法。

$('input.sortInp').change(function () {
    var input = $(this);

    input.parents('.float_left').find('.sortLoaderDiv').html('<img 
    class="sortLoader" src="/images/icons/loading_small1.gif">');

    setTimeout(function () {
        input.parents('.float_left').find('.sortLoaderDiv').html("Some text");
    }, 1000);

});

旁注:你可能不想拯救最顶层的big_list.each do |i| # sensitive stuff result = begin sensitive_method(i) nil rescue Exception => e e end # other sensitive stuff case result when Interrupt puts "done" break "done" when Exception then raise result end end ,但有些子类对救援有意义。

为了完成大部分操作:

Exception

答案 1 :(得分:2)

在主线程中引发了Interrupt异常。如果您使用辅助线程来处理列表,它将永远不会被中断。您将需要一种方法来告诉工作线程终止。在主线程中抢救中断并设置一个由孩子检查的标志就可以完成。

BigList = (1..100)

def sensitive_method(item)
  puts "start #{item}"
  sleep 1
  puts "halfway #{item}"
  sleep 1
  puts "done #{item}"
  puts
end

@done = false

thread = Thread.new do
  begin
    BigList.each do |item|
      break if @done
      sensitive_method item
    end
  end
end

begin
  thread.join
rescue Interrupt
  @done = true
  thread.join
end

答案 2 :(得分:0)

在rescue子句中使用的关键字ensure可用于此类情况,其中必须在发生异常后执行代码。

[-1, 0, 1].each do |i|
  begin
    puts "i=#{i} before exception"
    # <additional code>  
    n = 1/i
  rescue ZeroDivisionError => e
    puts "Exception: #{e}"
    exit
  ensure
    puts "Just executed 1/#{i}"
    # <additional code>  
  end
end

i=-1 before exception
Just executed 1/-1
i=0 before exception
Exception: divided by 0
Just executed 1/0

请注意,begin/rescue/ensure/end必须位于循环内,并且ensure之后的代码将针对每个i执行,无论是否发生零分割异常。