concurrent-ruby 1.3.3 → 1.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -2
- data/Gemfile +5 -5
- data/README.md +1 -1
- data/Rakefile +24 -19
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +1 -1
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +1 -1
- data/lib/concurrent-ruby/concurrent/agent.rb +2 -2
- data/lib/concurrent-ruby/concurrent/async.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atom.rb +1 -1
- data/lib/concurrent-ruby/concurrent/concern/logging.rb +17 -12
- data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent-ruby/concurrent/delay.rb +1 -1
- data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +1 -1
- data/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb +1 -1
- data/lib/concurrent-ruby/concurrent/map.rb +1 -1
- data/lib/concurrent-ruby/concurrent/promise.rb +1 -1
- data/lib/concurrent-ruby/concurrent/scheduled_task.rb +1 -1
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb +1 -1
- data/lib/concurrent-ruby/concurrent/synchronization/object.rb +1 -1
- data/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb +1 -1
- data/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb +1 -1
- data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +37 -7
- data/lib/concurrent-ruby/concurrent/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14d5a264c6fdc7b6087131a0f0a2fc1ce661d18029440e426e094443eb359ca6
|
4
|
+
data.tar.gz: 42e7b1b8fb885aec9b7b08488c6682af2743e65ad6dcd731f8c86d34f7768981
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31b6cf4fcc533349681610e74f6261c95e5c664583014d86101578f0380a6889288b29a89314a5da59e92cd422bcd97783c34d99c3e5c21a90db0f0d3fcc57e1
|
7
|
+
data.tar.gz: 4438de87d8ec3ff1cc6d7d246821002bbb76d5a9ddd8b77ebf4a15c0449f1509d694c4f57936b1e1a69e19f32736f21518fd8e82b8cdfbb99d5e2948976c230e
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
## Current
|
2
2
|
|
3
|
+
## Release v1.3.5, edge v0.7.2 (15 January 2025)
|
4
|
+
|
5
|
+
concurrent-ruby:
|
6
|
+
|
7
|
+
* (#1062) Remove dependency on logger.
|
8
|
+
|
9
|
+
concurrent-ruby-edge:
|
10
|
+
|
11
|
+
* (#1062) Remove dependency on logger.
|
12
|
+
|
13
|
+
## Release v1.3.4 (10 August 2024)
|
14
|
+
|
15
|
+
* (#1060) Fix bug with return value of `Concurrent.available_processor_count` when `cpu.cfs_quota_us` is -1.
|
16
|
+
* (#1058) Add `Concurrent.cpu_shares` that is cgroups aware.
|
17
|
+
|
3
18
|
## Release v1.3.3 (9 June 2024)
|
4
19
|
|
5
20
|
* (#1053) Improve the speed of `Concurrent.physical_processor_count` on Windows.
|
@@ -291,7 +306,7 @@ concurrent-ruby-edge:
|
|
291
306
|
* Simplification of `RubySingleThreadExecutor`
|
292
307
|
* `Async` improvements
|
293
308
|
- Each object uses its own `SingleThreadExecutor` instead of the global thread pool.
|
294
|
-
- No
|
309
|
+
- No longer supports executor injection
|
295
310
|
- Much better documentation
|
296
311
|
* `Atom` updates
|
297
312
|
- No longer `Dereferenceable`
|
@@ -466,7 +481,7 @@ Please see the [roadmap](https://github.com/ruby-concurrency/concurrent-ruby/iss
|
|
466
481
|
* Fixed bug with return value of `Concurrent::Actor::Utils::Pool#ask`
|
467
482
|
* Fixed timing bug in `TimerTask`
|
468
483
|
* Fixed bug when creating a `JavaThreadPoolExecutor` with minimum pool size of zero
|
469
|
-
* Removed confusing warning when not using native
|
484
|
+
* Removed confusing warning when not using native extensions
|
470
485
|
* Improved documentation
|
471
486
|
|
472
487
|
## Release v0.7.0 (13 August 2014)
|
data/Gemfile
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
version = File.read("#{__dir__}/lib/concurrent-ruby/concurrent/version.rb")[/'(.+)'/, 1] or raise
|
4
|
+
edge_version = File.read("#{__dir__}/lib/concurrent-ruby-edge/concurrent/edge/version.rb")[/'(.+)'/, 1] or raise
|
5
5
|
|
6
6
|
no_path = ENV['NO_PATH']
|
7
7
|
options = no_path ? {} : { path: '.' }
|
8
8
|
|
9
|
-
gem 'concurrent-ruby',
|
10
|
-
gem 'concurrent-ruby-edge',
|
11
|
-
gem 'concurrent-ruby-ext',
|
9
|
+
gem 'concurrent-ruby', version, options
|
10
|
+
gem 'concurrent-ruby-edge', edge_version, options
|
11
|
+
gem 'concurrent-ruby-ext', version, options.merge(platform: :mri)
|
12
12
|
|
13
13
|
group :development do
|
14
14
|
gem 'rake', '~> 13.0'
|
data/README.md
CHANGED
@@ -284,7 +284,7 @@ To use the tools in the Edge gem it must be required separately:
|
|
284
284
|
require 'concurrent-edge'
|
285
285
|
```
|
286
286
|
|
287
|
-
If the library does not behave as expected, `Concurrent.
|
287
|
+
If the library does not behave as expected, `Concurrent.use_simple_logger(:DEBUG)` could
|
288
288
|
help to reveal the problem.
|
289
289
|
|
290
290
|
## Installation
|
data/Rakefile
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require_relative 'lib/concurrent-ruby/concurrent/utility/engine'
|
1
|
+
version = File.read("#{__dir__}/lib/concurrent-ruby/concurrent/version.rb")[/'(.+)'/, 1] or raise
|
2
|
+
edge_version = File.read("#{__dir__}/lib/concurrent-ruby-edge/concurrent/edge/version.rb")[/'(.+)'/, 1] or raise
|
4
3
|
|
5
4
|
core_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby.gemspec')
|
6
5
|
ext_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-ext.gemspec')
|
@@ -8,14 +7,16 @@ edge_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-edge.
|
|
8
7
|
|
9
8
|
require 'rake/javaextensiontask'
|
10
9
|
|
11
|
-
ENV['JRUBY_HOME'] = ENV['CONCURRENT_JRUBY_HOME'] if ENV['CONCURRENT_JRUBY_HOME'] &&
|
10
|
+
ENV['JRUBY_HOME'] = ENV['CONCURRENT_JRUBY_HOME'] if ENV['CONCURRENT_JRUBY_HOME'] && RUBY_ENGINE != 'jruby'
|
12
11
|
|
13
12
|
Rake::JavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext|
|
14
13
|
ext.ext_dir = 'ext/concurrent-ruby'
|
15
14
|
ext.lib_dir = 'lib/concurrent-ruby/concurrent'
|
15
|
+
ext.source_version = '8'
|
16
|
+
ext.target_version = '8'
|
16
17
|
end
|
17
18
|
|
18
|
-
|
19
|
+
if RUBY_ENGINE == 'ruby'
|
19
20
|
require 'rake/extensiontask'
|
20
21
|
|
21
22
|
Rake::ExtensionTask.new('concurrent_ruby_ext', ext_gemspec) do |ext|
|
@@ -68,7 +69,7 @@ require 'rubygems'
|
|
68
69
|
require 'rubygems/package_task'
|
69
70
|
|
70
71
|
Gem::PackageTask.new(core_gemspec) {} if core_gemspec
|
71
|
-
Gem::PackageTask.new(ext_gemspec) {} if ext_gemspec &&
|
72
|
+
Gem::PackageTask.new(ext_gemspec) {} if ext_gemspec && RUBY_ENGINE != 'jruby'
|
72
73
|
Gem::PackageTask.new(edge_gemspec) {} if edge_gemspec
|
73
74
|
|
74
75
|
CLEAN.include(
|
@@ -96,9 +97,9 @@ begin
|
|
96
97
|
task :installed do
|
97
98
|
Bundler.with_original_env do
|
98
99
|
Dir.chdir(__dir__) do
|
99
|
-
sh "gem install pkg/concurrent-ruby-#{
|
100
|
-
sh "gem install pkg/concurrent-ruby-ext-#{
|
101
|
-
sh "gem install pkg/concurrent-ruby-edge-#{
|
100
|
+
sh "gem install pkg/concurrent-ruby-#{version}.gem"
|
101
|
+
sh "gem install pkg/concurrent-ruby-ext-#{version}.gem" if RUBY_ENGINE == 'ruby'
|
102
|
+
sh "gem install pkg/concurrent-ruby-edge-#{edge_version}.gem"
|
102
103
|
ENV['NO_PATH'] = 'true'
|
103
104
|
sh 'bundle update'
|
104
105
|
sh 'bundle exec rake spec:ci'
|
@@ -128,7 +129,7 @@ rescue LoadError => e
|
|
128
129
|
puts 'RSpec is not installed, skipping test task definitions: ' + e.message
|
129
130
|
end
|
130
131
|
|
131
|
-
current_yard_version_name =
|
132
|
+
current_yard_version_name = version
|
132
133
|
|
133
134
|
begin
|
134
135
|
require 'yard'
|
@@ -232,6 +233,8 @@ namespace :release do
|
|
232
233
|
# Depends on environment of @pitr-ch
|
233
234
|
|
234
235
|
task :checks do
|
236
|
+
raise '$CONCURRENT_JRUBY_HOME must be set' unless ENV['CONCURRENT_JRUBY_HOME']
|
237
|
+
|
235
238
|
Dir.chdir(__dir__) do
|
236
239
|
sh 'test -z "$(git status --porcelain)"' do |ok, res|
|
237
240
|
unless ok
|
@@ -262,6 +265,8 @@ namespace :release do
|
|
262
265
|
|
263
266
|
desc '* test actual installed gems instead of cloned repository on MRI and JRuby'
|
264
267
|
task :test do
|
268
|
+
raise '$CONCURRENT_JRUBY_HOME must be set' unless ENV['CONCURRENT_JRUBY_HOME']
|
269
|
+
|
265
270
|
Dir.chdir(__dir__) do
|
266
271
|
puts "Testing with the installed gem"
|
267
272
|
|
@@ -310,21 +315,21 @@ namespace :release do
|
|
310
315
|
desc '** tag HEAD with current version and push to github'
|
311
316
|
task :tag => :ask do
|
312
317
|
Dir.chdir(__dir__) do
|
313
|
-
sh "git tag v#{
|
314
|
-
sh "git push origin v#{
|
315
|
-
sh "git tag edge-v#{
|
316
|
-
sh "git push origin edge-v#{
|
318
|
+
sh "git tag v#{version}" if publish_base
|
319
|
+
sh "git push origin v#{version}" if publish_base
|
320
|
+
sh "git tag edge-v#{edge_version}" if publish_edge
|
321
|
+
sh "git push origin edge-v#{edge_version}" if publish_edge
|
317
322
|
end
|
318
323
|
end
|
319
324
|
|
320
325
|
desc '** push all *.gem files to rubygems'
|
321
326
|
task :rubygems => :ask do
|
322
327
|
Dir.chdir(__dir__) do
|
323
|
-
sh "gem push pkg/concurrent-ruby-#{
|
324
|
-
sh "gem push pkg/concurrent-ruby-edge-#{
|
325
|
-
sh "gem push pkg/concurrent-ruby-ext-#{
|
326
|
-
sh "gem push pkg/concurrent-ruby-ext-#{
|
327
|
-
sh "gem push pkg/concurrent-ruby-ext-#{
|
328
|
+
sh "gem push pkg/concurrent-ruby-#{version}.gem" if publish_base
|
329
|
+
sh "gem push pkg/concurrent-ruby-edge-#{edge_version}.gem" if publish_edge
|
330
|
+
sh "gem push pkg/concurrent-ruby-ext-#{version}.gem" if publish_base
|
331
|
+
sh "gem push pkg/concurrent-ruby-ext-#{version}-x64-mingw32.gem" if publish_base
|
332
|
+
sh "gem push pkg/concurrent-ruby-ext-#{version}-x86-mingw32.gem" if publish_base
|
328
333
|
end
|
329
334
|
end
|
330
335
|
|
@@ -481,7 +481,7 @@ public class ConcurrentHashMapV8<K, V>
|
|
481
481
|
*
|
482
482
|
* Maintaining API and serialization compatibility with previous
|
483
483
|
* versions of this class introduces several oddities. Mainly: We
|
484
|
-
* leave untouched but unused constructor arguments
|
484
|
+
* leave untouched but unused constructor arguments referring to
|
485
485
|
* concurrencyLevel. We accept a loadFactor constructor argument,
|
486
486
|
* but apply it only to initial table capacity (which is the only
|
487
487
|
* time that we can guarantee to honor it.) We also declare an
|
@@ -484,7 +484,7 @@ public class ConcurrentHashMapV8<K, V>
|
|
484
484
|
*
|
485
485
|
* Maintaining API and serialization compatibility with previous
|
486
486
|
* versions of this class introduces several oddities. Mainly: We
|
487
|
-
* leave untouched but unused constructor arguments
|
487
|
+
* leave untouched but unused constructor arguments referring to
|
488
488
|
* concurrencyLevel. We accept a loadFactor constructor argument,
|
489
489
|
* but apply it only to initial table capacity (which is the only
|
490
490
|
* time that we can guarantee to honor it.) We also declare an
|
@@ -371,7 +371,7 @@ module Concurrent
|
|
371
371
|
# @param [Float] timeout the maximum number of seconds to wait
|
372
372
|
# @return [Boolean] true if all actions complete before timeout
|
373
373
|
#
|
374
|
-
# @raise [Concurrent::TimeoutError] when
|
374
|
+
# @raise [Concurrent::TimeoutError] when timeout is reached
|
375
375
|
#
|
376
376
|
# @!macro agent_await_warning
|
377
377
|
def await_for!(timeout)
|
@@ -477,7 +477,7 @@ module Concurrent
|
|
477
477
|
# @param [Array<Concurrent::Agent>] agents the Agents on which to wait
|
478
478
|
# @return [Boolean] true if all actions complete before timeout
|
479
479
|
#
|
480
|
-
# @raise [Concurrent::TimeoutError] when
|
480
|
+
# @raise [Concurrent::TimeoutError] when timeout is reached
|
481
481
|
# @!macro agent_await_warning
|
482
482
|
def await_for!(timeout, *agents)
|
483
483
|
raise Concurrent::TimeoutError unless await_for(timeout, *agents)
|
@@ -218,7 +218,7 @@ module Concurrent
|
|
218
218
|
|
219
219
|
# @!method self.new(*args, &block)
|
220
220
|
#
|
221
|
-
#
|
221
|
+
# Instantiate a new object and ensure proper initialization of the
|
222
222
|
# synchronization mechanisms.
|
223
223
|
#
|
224
224
|
# @param [Array<Object>] args Zero or more arguments to be passed to the
|
@@ -113,7 +113,7 @@ module Concurrent
|
|
113
113
|
# @option opts [Proc] :validator (nil) Optional proc used to validate new
|
114
114
|
# values. It must accept one and only one argument which will be the
|
115
115
|
# intended new value. The validator will return true if the new value
|
116
|
-
# is acceptable else return false (
|
116
|
+
# is acceptable else return false (preferably) or raise an exception.
|
117
117
|
#
|
118
118
|
# @!macro deref_options
|
119
119
|
#
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'logger'
|
2
1
|
require 'concurrent/atomic/atomic_reference'
|
3
2
|
|
4
3
|
module Concurrent
|
@@ -8,10 +7,12 @@ module Concurrent
|
|
8
7
|
#
|
9
8
|
# @!visibility private
|
10
9
|
module Logging
|
11
|
-
|
10
|
+
# The same as Logger::Severity but we copy it here to avoid a dependency on the logger gem just for these 7 constants
|
11
|
+
DEBUG, INFO, WARN, ERROR, FATAL, UNKNOWN = 0, 1, 2, 3, 4, 5
|
12
|
+
SEV_LABEL = %w[DEBUG INFO WARN ERROR FATAL ANY].freeze
|
12
13
|
|
13
14
|
# Logs through {Concurrent.global_logger}, it can be overridden by setting @logger
|
14
|
-
# @param [Integer] level one of
|
15
|
+
# @param [Integer] level one of Concurrent::Concern::Logging constants
|
15
16
|
# @param [String] progname e.g. a path of an Actor
|
16
17
|
# @param [String, nil] message when nil block is used to generate the message
|
17
18
|
# @yieldreturn [String] a message
|
@@ -23,7 +24,7 @@ module Concurrent
|
|
23
24
|
end
|
24
25
|
logger.call level, progname, message, &block
|
25
26
|
rescue => error
|
26
|
-
$stderr.puts "`Concurrent.
|
27
|
+
$stderr.puts "`Concurrent.global_logger` failed to log #{[level, progname, message, block]}\n" +
|
27
28
|
"#{error.message} (#{error.class})\n#{error.backtrace.join "\n"}"
|
28
29
|
end
|
29
30
|
end
|
@@ -33,8 +34,10 @@ end
|
|
33
34
|
module Concurrent
|
34
35
|
extend Concern::Logging
|
35
36
|
|
36
|
-
#
|
37
|
-
def self.create_simple_logger(level =
|
37
|
+
# Create a simple logger with provided level and output.
|
38
|
+
def self.create_simple_logger(level = :FATAL, output = $stderr)
|
39
|
+
level = Concern::Logging.const_get(level) unless level.is_a?(Integer)
|
40
|
+
|
38
41
|
# TODO (pitr-ch 24-Dec-2016): figure out why it had to be replaced, stdlogger was deadlocking
|
39
42
|
lambda do |severity, progname, message = nil, &block|
|
40
43
|
return false if severity < level
|
@@ -52,7 +55,7 @@ module Concurrent
|
|
52
55
|
|
53
56
|
output.print format "[%s] %5s -- %s: %s\n",
|
54
57
|
Time.now.strftime('%Y-%m-%d %H:%M:%S.%L'),
|
55
|
-
|
58
|
+
Concern::Logging::SEV_LABEL[severity],
|
56
59
|
progname,
|
57
60
|
formatted_message
|
58
61
|
true
|
@@ -60,13 +63,15 @@ module Concurrent
|
|
60
63
|
end
|
61
64
|
|
62
65
|
# Use logger created by #create_simple_logger to log concurrent-ruby messages.
|
63
|
-
def self.use_simple_logger(level =
|
66
|
+
def self.use_simple_logger(level = :FATAL, output = $stderr)
|
64
67
|
Concurrent.global_logger = create_simple_logger level, output
|
65
68
|
end
|
66
69
|
|
67
|
-
#
|
70
|
+
# Create a stdlib logger with provided level and output.
|
71
|
+
# If you use this deprecated method you might need to add logger to your Gemfile to avoid warnings from Ruby 3.3.5+.
|
68
72
|
# @deprecated
|
69
|
-
def self.create_stdlib_logger(level =
|
73
|
+
def self.create_stdlib_logger(level = :FATAL, output = $stderr)
|
74
|
+
require 'logger'
|
70
75
|
logger = Logger.new(output)
|
71
76
|
logger.level = level
|
72
77
|
logger.formatter = lambda do |severity, datetime, progname, msg|
|
@@ -93,7 +98,7 @@ module Concurrent
|
|
93
98
|
|
94
99
|
# Use logger created by #create_stdlib_logger to log concurrent-ruby messages.
|
95
100
|
# @deprecated
|
96
|
-
def self.use_stdlib_logger(level =
|
101
|
+
def self.use_stdlib_logger(level = :FATAL, output = $stderr)
|
97
102
|
Concurrent.global_logger = create_stdlib_logger level, output
|
98
103
|
end
|
99
104
|
|
@@ -103,7 +108,7 @@ module Concurrent
|
|
103
108
|
NULL_LOGGER = lambda { |level, progname, message = nil, &block| }
|
104
109
|
|
105
110
|
# @!visibility private
|
106
|
-
GLOBAL_LOGGER = AtomicReference.new(create_simple_logger(
|
111
|
+
GLOBAL_LOGGER = AtomicReference.new(create_simple_logger(:WARN))
|
107
112
|
private_constant :GLOBAL_LOGGER
|
108
113
|
|
109
114
|
def self.global_logger
|
Binary file
|
@@ -19,7 +19,7 @@ module Concurrent
|
|
19
19
|
#
|
20
20
|
# When a `Delay` is created its state is set to `pending`. The value and
|
21
21
|
# reason are both `nil`. The first time the `#value` method is called the
|
22
|
-
# enclosed
|
22
|
+
# enclosed operation will be run and the calling thread will block. Other
|
23
23
|
# threads attempting to call `#value` will block as well. Once the operation
|
24
24
|
# is complete the *value* will be set to the result of the operation or the
|
25
25
|
# *reason* will be set to the raised exception, as appropriate. All threads
|
@@ -83,7 +83,7 @@ module Concurrent
|
|
83
83
|
#
|
84
84
|
# This is a no-op on some pool implementation (e.g. the Java one). The Ruby
|
85
85
|
# pool will auto-prune each time a new job is posted. You will need to call
|
86
|
-
# this method
|
86
|
+
# this method explicitly in case your application post jobs in bursts (a
|
87
87
|
# lot of jobs and then nothing for long periods)
|
88
88
|
|
89
89
|
# @!macro thread_pool_executor_public_api
|
@@ -27,7 +27,7 @@ module Concurrent
|
|
27
27
|
# is received. This pattern has several issues. The thread itself is highly
|
28
28
|
# susceptible to errors during processing. Also, the thread itself must be
|
29
29
|
# constantly monitored and restarted should it die. `SingleThreadExecutor`
|
30
|
-
# encapsulates all these
|
30
|
+
# encapsulates all these behaviors. The task processor is highly resilient
|
31
31
|
# to errors from within tasks. Also, should the thread die it will
|
32
32
|
# automatically be restarted.
|
33
33
|
#
|
@@ -148,7 +148,7 @@ module Concurrent
|
|
148
148
|
if value = super # non-falsy value is an existing mapping, return it right away
|
149
149
|
value
|
150
150
|
# re-check is done with get_or_default(key, NULL) instead of a simple !key?(key) in order to avoid a race condition, whereby by the time the current thread gets to the key?(key) call
|
151
|
-
# a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an
|
151
|
+
# a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrect +nil+ value
|
152
152
|
# would be returned)
|
153
153
|
# note: nil == value check is not technically necessary
|
154
154
|
elsif @default_proc && nil == value && NULL == (value = get_or_default(key, NULL))
|
@@ -103,7 +103,7 @@ module Concurrent
|
|
103
103
|
# - if parent is *rejected* the child will be *pending* (but will ultimately be *rejected*)
|
104
104
|
#
|
105
105
|
# Promises are executed asynchronously from the main thread. By the time a
|
106
|
-
# child Promise finishes
|
106
|
+
# child Promise finishes initialization it may be in a different state than its
|
107
107
|
# parent (by the time a child is created its parent may have completed
|
108
108
|
# execution and changed state). Despite being asynchronous, however, the order
|
109
109
|
# of execution of Promise objects in a chain (or tree) is strictly defined.
|
@@ -157,7 +157,7 @@ module Concurrent
|
|
157
157
|
end
|
158
158
|
end
|
159
159
|
members.each_with_index do |member, index|
|
160
|
-
clazz.send :remove_method, member if clazz.instance_methods.include? member
|
160
|
+
clazz.send :remove_method, member if clazz.instance_methods(false).include? member
|
161
161
|
clazz.send(:define_method, member) do
|
162
162
|
@values[index]
|
163
163
|
end
|
@@ -58,7 +58,7 @@ module Concurrent
|
|
58
58
|
|
59
59
|
# Creates methods for reading and writing to a instance variable with
|
60
60
|
# volatile (Java) semantic as {.attr_volatile} does.
|
61
|
-
# The instance variable should be accessed
|
61
|
+
# The instance variable should be accessed only through generated methods.
|
62
62
|
# This method generates following methods: `value`, `value=(new_value) #=> new_value`,
|
63
63
|
# `swap_value(new_value) #=> old_value`,
|
64
64
|
# `compare_and_set_value(expected, value) #=> true || false`, `update_value(&block)`.
|
@@ -9,7 +9,7 @@ module Concurrent
|
|
9
9
|
# @!visibility private
|
10
10
|
module Util
|
11
11
|
|
12
|
-
# A Ruby port of the Doug Lea's jsr166e.
|
12
|
+
# A Ruby port of the Doug Lea's jsr166e.LongAdder class version 1.8
|
13
13
|
# available in public domain.
|
14
14
|
#
|
15
15
|
# Original source code available here:
|
@@ -15,7 +15,7 @@ module Concurrent
|
|
15
15
|
# Usage:
|
16
16
|
# x = XorShiftRandom.get # uses Kernel.rand to generate an initial seed
|
17
17
|
# while true
|
18
|
-
# if (x = XorShiftRandom.xorshift).odd? # thread-
|
18
|
+
# if (x = XorShiftRandom.xorshift).odd? # thread-locally generate a next random number
|
19
19
|
# do_something_at_random
|
20
20
|
# end
|
21
21
|
# end
|
@@ -12,6 +12,7 @@ module Concurrent
|
|
12
12
|
@processor_count = Delay.new { compute_processor_count }
|
13
13
|
@physical_processor_count = Delay.new { compute_physical_processor_count }
|
14
14
|
@cpu_quota = Delay.new { compute_cpu_quota }
|
15
|
+
@cpu_shares = Delay.new { compute_cpu_shares }
|
15
16
|
end
|
16
17
|
|
17
18
|
def processor_count
|
@@ -41,6 +42,10 @@ module Concurrent
|
|
41
42
|
@cpu_quota.value
|
42
43
|
end
|
43
44
|
|
45
|
+
def cpu_shares
|
46
|
+
@cpu_shares.value
|
47
|
+
end
|
48
|
+
|
44
49
|
private
|
45
50
|
|
46
51
|
def compute_processor_count
|
@@ -78,7 +83,7 @@ module Concurrent
|
|
78
83
|
# Bail out if both commands returned something unexpected
|
79
84
|
processor_count
|
80
85
|
else
|
81
|
-
# powershell: "\nNumberOfCores\n-------------\n 4\n\n\n"
|
86
|
+
# powershell: "\nNumberOfCores\n-------------\n 4\n\n\n"
|
82
87
|
# wmic: "NumberOfCores \n\n4 \n\n\n\n"
|
83
88
|
result.scan(/\d+/).map(&:to_i).reduce(:+)
|
84
89
|
end
|
@@ -107,12 +112,28 @@ module Concurrent
|
|
107
112
|
elsif File.exist?("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us")
|
108
113
|
# cgroups v1: https://kernel.googlesource.com/pub/scm/linux/kernel/git/glommer/memcg/+/cpu_stat/Documentation/cgroups/cpu.txt
|
109
114
|
max = File.read("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us").to_i
|
110
|
-
|
115
|
+
# If the cpu.cfs_quota_us is -1, cgroup does not adhere to any CPU time restrictions
|
116
|
+
# https://docs.kernel.org/scheduler/sched-bwc.html#management
|
117
|
+
return nil if max <= 0
|
111
118
|
period = File.read("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us").to_f
|
112
119
|
max / period
|
113
120
|
end
|
114
121
|
end
|
115
122
|
end
|
123
|
+
|
124
|
+
def compute_cpu_shares
|
125
|
+
if RbConfig::CONFIG["target_os"].include?("linux")
|
126
|
+
if File.exist?("/sys/fs/cgroup/cpu.weight")
|
127
|
+
# cgroups v2: https://docs.kernel.org/admin-guide/cgroup-v2.html#cpu-interface-files
|
128
|
+
# Ref: https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2254-cgroup-v2#phase-1-convert-from-cgroups-v1-settings-to-v2
|
129
|
+
weight = File.read("/sys/fs/cgroup/cpu.weight").to_f
|
130
|
+
((((weight - 1) * 262142) / 9999) + 2) / 1024
|
131
|
+
elsif File.exist?("/sys/fs/cgroup/cpu/cpu.shares")
|
132
|
+
# cgroups v1: https://kernel.googlesource.com/pub/scm/linux/kernel/git/glommer/memcg/+/cpu_stat/Documentation/cgroups/cpu.txt
|
133
|
+
File.read("/sys/fs/cgroup/cpu/cpu.shares").to_f / 1024
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
116
137
|
end
|
117
138
|
end
|
118
139
|
|
@@ -128,8 +149,8 @@ module Concurrent
|
|
128
149
|
# `java.lang.Runtime.getRuntime.availableProcessors` will be used. According
|
129
150
|
# to the Java documentation this "value may change during a particular
|
130
151
|
# invocation of the virtual machine... [applications] should therefore
|
131
|
-
# occasionally poll this property."
|
132
|
-
#
|
152
|
+
# occasionally poll this property." We still memoize this value once under
|
153
|
+
# JRuby.
|
133
154
|
#
|
134
155
|
# Otherwise Ruby's Etc.nprocessors will be used.
|
135
156
|
#
|
@@ -162,13 +183,14 @@ module Concurrent
|
|
162
183
|
end
|
163
184
|
|
164
185
|
# Number of processors cores available for process scheduling.
|
165
|
-
#
|
166
|
-
#
|
186
|
+
# This method takes in account the CPU quota if the process is inside a cgroup with a
|
187
|
+
# dedicated CPU quota (typically Docker).
|
188
|
+
# Otherwise it returns the same value as #processor_count but as a Float.
|
167
189
|
#
|
168
190
|
# For performance reasons the calculated value will be memoized on the first
|
169
191
|
# call.
|
170
192
|
#
|
171
|
-
# @return [
|
193
|
+
# @return [Float] number of available processors
|
172
194
|
def self.available_processor_count
|
173
195
|
processor_counter.available_processor_count
|
174
196
|
end
|
@@ -187,4 +209,12 @@ module Concurrent
|
|
187
209
|
def self.cpu_quota
|
188
210
|
processor_counter.cpu_quota
|
189
211
|
end
|
212
|
+
|
213
|
+
# The CPU shares requested by the process. For performance reasons the calculated
|
214
|
+
# value will be memoized on the first call.
|
215
|
+
#
|
216
|
+
# @return [Float, nil] CPU shares requested by the process, or nil if not set
|
217
|
+
def self.cpu_shares
|
218
|
+
processor_counter.cpu_shares
|
219
|
+
end
|
190
220
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: concurrent-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jerry D'Antonio
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2025-01-15 00:00:00.000000000 Z
|
14
14
|
dependencies: []
|
15
15
|
description: |
|
16
16
|
Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more.
|