From 39f56306265432e9bef8f8fb88486279eae416f2 Mon Sep 17 00:00:00 2001 From: Yuji Yaginuma Date: Thu, 8 Aug 2024 11:19:07 +0900 Subject: [PATCH] Use cgroups aware processor count by default In containerized environments, a number of CPU cores isn't the same as the available CPUs. In this case, we need to consider cgroups. `concurrent-ruby` now has the method to get that since v1.3.1. I think it's better to use this for setting more container environment friendly default value. Ref: https://github.com/ruby-concurrency/concurrent-ruby/pull/1038 I keep `Parallel.processor_count` as is to keep supporting setting processor count via env(`PARALLEL_PROCESSOR_COUNT`). --- Readme.md | 1 + lib/parallel.rb | 14 +++++++++++--- spec/parallel_spec.rb | 5 ----- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Readme.md b/Readme.md index ade2cfc..8168b89 100644 --- a/Readme.md +++ b/Readme.md @@ -196,6 +196,7 @@ Tips - [Isolation] Do not reuse previous worker processes: `isolation: true` - [Stop all processes with an alternate interrupt signal] `'INT'` (from `ctrl+c`) is caught by default. Catch `'TERM'` (from `kill`) with `interrupt_signal: 'TERM'` - [Process count via ENV] `PARALLEL_PROCESSOR_COUNT=16` will use `16` instead of the number of processors detected. This is used to reconfigure a tool using `parallel` without inserting custom logic. + - [Process count] `parallel` uses a number of processors seen by the OS for process count by default. If you want to use a value considering CPU quota, please add `concurrent-ruby` to your `Gemfile`. TODO ==== diff --git a/lib/parallel.rb b/lib/parallel.rb index 409677b..bd482a3 100644 --- a/lib/parallel.rb +++ b/lib/parallel.rb @@ -337,10 +337,10 @@ def physical_processor_count end end - # Number of processors seen by the OS, used for process scheduling + # Number of processors seen by the OS or value considering CPU quota if the process is inside a cgroup, + # used for process scheduling def processor_count - require 'etc' - @processor_count ||= Integer(ENV['PARALLEL_PROCESSOR_COUNT'] || Etc.nprocessors) + @processor_count ||= Integer(ENV['PARALLEL_PROCESSOR_COUNT'] || available_processor_count) end def worker_number @@ -695,5 +695,13 @@ def instrument_start(item, index, options) return unless (on_start = options[:start]) options[:mutex].synchronize { on_start.call(item, index) } end + + def available_processor_count + require 'concurrent-ruby' + Concurrent.available_processor_count.floor + rescue LoadError, NoMethodError + require 'etc' + Etc.nprocessors + end end end diff --git a/spec/parallel_spec.rb b/spec/parallel_spec.rb index 2388e28..8ec853a 100644 --- a/spec/parallel_spec.rb +++ b/spec/parallel_spec.rb @@ -49,11 +49,6 @@ def without_ractor_warning(out) (1..999).should include(Parallel.processor_count) end end - - it 'uses Etc.nprocessors in Ruby 2.2+' do - defined?(Etc).should == "constant" - Etc.respond_to?(:nprocessors).should == true - end end describe ".physical_processor_count" do