Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在并发ruby线程池中处理异常_Ruby_Multithreading_Concurrency_Concurrent Ruby - Fatal编程技术网

在并发ruby线程池中处理异常

在并发ruby线程池中处理异常,ruby,multithreading,concurrency,concurrent-ruby,Ruby,Multithreading,Concurrency,Concurrent Ruby,如何处理并发ruby线程池()中的异常 例如: pool = Concurrent::FixedThreadPool.new(5) pool.post do raise 'something goes wrong' end # how to rescue this exception here 更新: 以下是我的代码的简化版本: def process pool = Concurrent::FixedThreadPool.new(5) products.each do |p

如何处理并发ruby线程池()中的异常

例如:

pool = Concurrent::FixedThreadPool.new(5) 
pool.post do
  raise 'something goes wrong'
end

# how to rescue this exception here

更新:

以下是我的代码的简化版本:

def process
  pool = Concurrent::FixedThreadPool.new(5)

  products.each do |product|
    new_product = generate_new_product

    pool.post do
      store_in_db(new_product) # here exception is raised, e.g. connection to db failed
    end
  end

  pool.shutdown
  pool.wait_for_terminaton
end
所以我想要实现的是,在出现异常时停止处理(中断循环)


在更高级别的应用程序中也会解救此异常,并执行一些清理作业(如将模型状态设置为failure并发送一些通知)。

可能有更好的方法,但这确实有效。您需要更改
等待\u池\u完成中的错误处理

def process
  pool = Concurrent::FixedThreadPool.new(10)
  errors = Concurrent::Array.new

  10_000.times do
    pool.post do
      begin
        # do the work
      rescue StandardError => e
        errors << e
      end
    end
  end
  wait_for_pool_to_finish(pool, errors)
end

private

def wait_for_pool_to_finish(pool, errors)
  pool.shutdown

  until pool.shutdown?
    if errors.any?
      pool.kill
      fail errors.first
    end
    sleep 1
  end

  pool.wait_for_termination
end
def过程
pool=Concurrent::FixedThreadPool.new(10)
errors=Concurrent::Array.new
一万倍
pool.post do
开始
#做这项工作
营救标准错误=>e

错误下面的答案来自这里

" 大多数应用程序不应直接使用线程池。线程池是供内部使用的低级抽象。此库中的所有高级抽象(Promise、Actor等)都将作业发布到全局线程池并提供异常处理。只需选择最适合您的用例的抽象并使用它

如果您觉得需要配置自己的线程池而不是使用全局线程池,则仍然可以使用高级抽象。它们都支持:executor选项,允许您注入自定义线程池。然后,您可以使用高级抽象提供的异常处理

如果您绝对坚持将作业直接发布到线程池,而不是使用我们的高级抽象(我强烈反对),那么只需创建一个作业包装器。您可以在所有高级抽象、Rails ActiveJob、Stuck Punch和其他使用我们线程池的库中找到作业包装器的示例。”

那么,有承诺的实施如何? 在您的情况下,它看起来像这样:

promises = []
products.each do |product|
  new_product = generate_new_prodcut

  promises << Concurrent::Promise.execute do 
    store_in_db(new_product)
  end
end

# .value will wait for the Thread to finish.
# The ! means, that all exceptions will be propagated to the main thread
# .zip will make one Promise which contains all other promises.
Concurrent::Promise.zip(*promises).value!
promissions=[]
产品。每个do |产品|
新产品=生成新产品
承诺我制造了一个问题。并发线程池可以毫无问题地支持可中止工作线程

require "concurrent"

Concurrent::RubyThreadPoolExecutor.class_eval do
  # Inspired by "ns_kill_execution".
  def ns_abort_execution aborted_worker
    @pool.each do |worker|
      next if worker == aborted_worker
      worker.kill
    end

    @pool = [aborted_worker]
    @ready.clear

    stopped_event.set
    nil
  end

  def abort_worker worker
    synchronize do
      ns_abort_execution worker
    end
    nil
  end

  def join
    shutdown

    # We should wait for stopped event.
    # We couldn't use timeout.
    stopped_event.wait nil

    @pool.each do |aborted_worker|
      # Rubinius could receive an error from aborted thread's "join" only.
      # MRI Ruby doesn't care about "join".
      # It will receive error anyway.

      # We can "raise" error in aborted thread and than "join" it from this thread.
      # We can "join" aborted thread from this thread and than "raise" error in aborted thread.
      # The order of "raise" and "join" is not important. We will receive target error anyway.

      aborted_worker.join
    end

    @pool.clear
    nil
  end

  class AbortableWorker < self.const_get :Worker
    def initialize pool
      super
      @thread.abort_on_exception = true
    end

    def run_task pool, task, args
      begin
        task.call *args
      rescue StandardError => error
        pool.abort_worker self
        raise error
      end

      pool.worker_task_completed
      nil
    end

    def join
      @thread.join
      nil
    end
  end

  self.send :remove_const, :Worker
  self.const_set :Worker, AbortableWorker
end

class MyError < StandardError; end

pool = Concurrent::FixedThreadPool.new 5

begin
  pool.post do
    sleep 1
    puts "we shouldn't receive this message"
  end

  pool.post do
    puts "raising my error"
    raise MyError
  end

  pool.join

rescue MyError => error
  puts "received my error, trace: \n#{error.backtrace.join("\n")}"
end

sleep 2

此补丁适用于任何版本的MRI Ruby和Rubinius。JRuby不工作,我不在乎。如果你想支持JRuby executor,请给它打补丁。这应该很容易。

这取决于发生什么样的异常以及您希望如何响应。请扩展您的示例。我更新了原始帖子,并提供了更多解释。您是否寻找了合适的
:回退\u策略
?回退策略只告诉您当超过最大队列大小或池关闭时如何处理被拒绝的任务。我们也为此苦苦挣扎了几个月。因为似乎真的没有任何合理的文献,我问开发者:希望他们会回答。这不是一个合理的答案。任何应用程序都应该能够直接使用公共api,因为它是公共的。这个api应该对用户透明。它不应该只忽略例外,这实际上与我的答案无关。正如我们在这里看到的,这是你的观点,显然不是每个人的观点。我不是说你错了,也许你的方式更好。但我提供了一种处理他的问题的方法,即使这不是最好的答案,也是一个完全有效的答案,为我们解决了问题。我看到了你的方法的优点,但是否决票完全是基于你的意见!你让人们把线程池变成承诺只是因为。。。线程池不希望支持可中止的工作线程。xDD是的,我认为点击-1按钮就足够了。不,我什么也没给他们,我让他们知道官方的github回购协议中有什么答案。这是对SO的一个有效贡献。如何使用承诺之类的高级抽象来控制并发性?这一直是我最关心的问题,我无法在文档中找到任何答案。
raising my error
received my error, trace:
...