我应该如何使用 Concurrent-Ruby 限制线程创建?
How ought I limit Thread creation using Concurrent-Ruby?
我有一个进程使用 concurrent-ruby gem 使用 Concurrent::Future.execute
同时处理大量 API 调用,一段时间后,它死了:
ERROR -- : can't create Thread (11) (ThreadError)
/current/vendor/bundler_gems/ruby/2.0.0/bundler/gems/concurrent-ruby-cba3702c4e1e/lib/concurrent/executor/ruby_thread_pool_executor.rb:280:in `initialize'
有没有一种简单的方法可以告诉 Concurrent
限制它生成的线程数,因为我无法提前知道它需要多少次 API 调用制作?
或者这是我需要在我的应用程序中明确编码的内容吗?
我正在使用 Ruby 2.0.0
(唉,目前无法更改它)
对此的典型答案是创建一个线程池。
创建有限数量的线程,有办法记录哪些是活动的,哪些不是。当一个线程完成一个 API 调用时,将其标记为非活动状态,以便它可以处理下一个调用。
您正在使用的 gem 已经有线程池。
经过一些阅读和反复试验,我得出了以下解决方案。在这里发帖以防对其他人有帮助。
您可以通过指定 RubyThreadPoolExecutor
1
来控制 Concurrent
使用线程的方式
因此,在我的例子中,代码如下所示:
threadPool = Concurrent::ThreadPoolExecutor.new(
min_threads: [2, Concurrent.processor_count].min,
max_threads: [2, Concurrent.processor_count].max,
max_queue: [2, Concurrent.processor_count].max * 5,
overflow_policy: :caller_runs
)
result_things = massive_list_of_things.map do |thing|
(Concurrent::Future.new executor: threadPool do
expensive_api_call using: thing
end).execute
end
所以在我的笔记本电脑上我有 4 个处理器,所以这样它将使用 2 到 4 个线程,并在强制执行使用调用线程之前允许队列中最多 20 个线程。当线程释放时,并发库将重新分配它们。
然而,为 max_queue
值选择正确的乘数看起来像是一个反复试验的问题;但 5
是一个合理的猜测。
1 实际文档描述了一种不同的方法,但实际代码与文档不一致,所以我在这里展示的代码是基于实际有效的方法。
我有一个进程使用 concurrent-ruby gem 使用 Concurrent::Future.execute
同时处理大量 API 调用,一段时间后,它死了:
ERROR -- : can't create Thread (11) (ThreadError)
/current/vendor/bundler_gems/ruby/2.0.0/bundler/gems/concurrent-ruby-cba3702c4e1e/lib/concurrent/executor/ruby_thread_pool_executor.rb:280:in `initialize'
有没有一种简单的方法可以告诉 Concurrent
限制它生成的线程数,因为我无法提前知道它需要多少次 API 调用制作?
或者这是我需要在我的应用程序中明确编码的内容吗?
我正在使用 Ruby 2.0.0
(唉,目前无法更改它)
对此的典型答案是创建一个线程池。
创建有限数量的线程,有办法记录哪些是活动的,哪些不是。当一个线程完成一个 API 调用时,将其标记为非活动状态,以便它可以处理下一个调用。
您正在使用的 gem 已经有线程池。
经过一些阅读和反复试验,我得出了以下解决方案。在这里发帖以防对其他人有帮助。
您可以通过指定 RubyThreadPoolExecutor
1
Concurrent
使用线程的方式
因此,在我的例子中,代码如下所示:
threadPool = Concurrent::ThreadPoolExecutor.new(
min_threads: [2, Concurrent.processor_count].min,
max_threads: [2, Concurrent.processor_count].max,
max_queue: [2, Concurrent.processor_count].max * 5,
overflow_policy: :caller_runs
)
result_things = massive_list_of_things.map do |thing|
(Concurrent::Future.new executor: threadPool do
expensive_api_call using: thing
end).execute
end
所以在我的笔记本电脑上我有 4 个处理器,所以这样它将使用 2 到 4 个线程,并在强制执行使用调用线程之前允许队列中最多 20 个线程。当线程释放时,并发库将重新分配它们。
然而,为 max_queue
值选择正确的乘数看起来像是一个反复试验的问题;但 5
是一个合理的猜测。
1 实际文档描述了一种不同的方法,但实际代码与文档不一致,所以我在这里展示的代码是基于实际有效的方法。