concurrent-ruby 1.1.8 → 1.1.10
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 +26 -0
- data/Gemfile +2 -7
- data/README.md +40 -20
- data/Rakefile +26 -31
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +0 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +52 -22
- data/lib/concurrent-ruby/concurrent/async.rb +1 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +1 -0
- data/lib/concurrent-ruby/concurrent/atomic/event.rb +2 -2
- data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +18 -2
- data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +4 -6
- data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +26 -5
- data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
- data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +11 -1
- data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +16 -13
- data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +13 -3
- data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +1 -1
- data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +4 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +10 -4
- data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +26 -37
- data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +5 -5
- data/lib/concurrent-ruby/concurrent/map.rb +13 -4
- data/lib/concurrent-ruby/concurrent/promise.rb +1 -0
- data/lib/concurrent-ruby/concurrent/scheduled_task.rb +29 -16
- data/lib/concurrent-ruby/concurrent/set.rb +14 -6
- data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +1 -3
- data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +12 -0
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +6 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +26 -1
- data/lib/concurrent-ruby/concurrent/timer_task.rb +11 -33
- data/lib/concurrent-ruby/concurrent/tvar.rb +20 -60
- data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +67 -35
- data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +2 -35
- data/lib/concurrent-ruby/concurrent/version.rb +1 -1
- data/lib/concurrent-ruby/concurrent-ruby.rb +5 -1
- metadata +8 -7
|
@@ -15,7 +15,6 @@ module Concurrent
|
|
|
15
15
|
# Create a new `TVar` with an initial value.
|
|
16
16
|
def initialize(value)
|
|
17
17
|
@value = value
|
|
18
|
-
@version = 0
|
|
19
18
|
@lock = Mutex.new
|
|
20
19
|
end
|
|
21
20
|
|
|
@@ -43,16 +42,6 @@ module Concurrent
|
|
|
43
42
|
@value = value
|
|
44
43
|
end
|
|
45
44
|
|
|
46
|
-
# @!visibility private
|
|
47
|
-
def unsafe_version # :nodoc:
|
|
48
|
-
@version
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# @!visibility private
|
|
52
|
-
def unsafe_increment_version # :nodoc:
|
|
53
|
-
@version += 1
|
|
54
|
-
end
|
|
55
|
-
|
|
56
45
|
# @!visibility private
|
|
57
46
|
def unsafe_lock # :nodoc:
|
|
58
47
|
@lock
|
|
@@ -164,53 +153,39 @@ module Concurrent
|
|
|
164
153
|
|
|
165
154
|
ABORTED = ::Object.new
|
|
166
155
|
|
|
167
|
-
|
|
156
|
+
OpenEntry = Struct.new(:value, :modified)
|
|
168
157
|
|
|
169
158
|
AbortError = Class.new(StandardError)
|
|
170
159
|
LeaveError = Class.new(StandardError)
|
|
171
160
|
|
|
172
161
|
def initialize
|
|
173
|
-
@
|
|
174
|
-
@write_log = {}
|
|
162
|
+
@open_tvars = {}
|
|
175
163
|
end
|
|
176
164
|
|
|
177
165
|
def read(tvar)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if @write_log.has_key? tvar
|
|
181
|
-
@write_log[tvar]
|
|
182
|
-
else
|
|
183
|
-
@read_log.push(ReadLogEntry.new(tvar, tvar.unsafe_version))
|
|
184
|
-
tvar.unsafe_value
|
|
185
|
-
end
|
|
166
|
+
entry = open(tvar)
|
|
167
|
+
entry.value
|
|
186
168
|
end
|
|
187
169
|
|
|
188
170
|
def write(tvar, value)
|
|
189
|
-
|
|
171
|
+
entry = open(tvar)
|
|
172
|
+
entry.modified = true
|
|
173
|
+
entry.value = value
|
|
174
|
+
end
|
|
190
175
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
@write_log[tvar] = value
|
|
194
|
-
else
|
|
195
|
-
# Try to lock the TVar
|
|
176
|
+
def open(tvar)
|
|
177
|
+
entry = @open_tvars[tvar]
|
|
196
178
|
|
|
179
|
+
unless entry
|
|
197
180
|
unless tvar.unsafe_lock.try_lock
|
|
198
|
-
# Someone else is writing to this TVar - abort
|
|
199
181
|
Concurrent::abort_transaction
|
|
200
182
|
end
|
|
201
183
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
@write_log[tvar] = value
|
|
205
|
-
|
|
206
|
-
# If we previously read from it, check the version hasn't changed
|
|
207
|
-
|
|
208
|
-
@read_log.each do |log_entry|
|
|
209
|
-
if log_entry.tvar == tvar and tvar.unsafe_version > log_entry.version
|
|
210
|
-
Concurrent::abort_transaction
|
|
211
|
-
end
|
|
212
|
-
end
|
|
184
|
+
entry = OpenEntry.new(tvar.unsafe_value, false)
|
|
185
|
+
@open_tvars[tvar] = entry
|
|
213
186
|
end
|
|
187
|
+
|
|
188
|
+
entry
|
|
214
189
|
end
|
|
215
190
|
|
|
216
191
|
def abort
|
|
@@ -218,32 +193,17 @@ module Concurrent
|
|
|
218
193
|
end
|
|
219
194
|
|
|
220
195
|
def commit
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
tvar.unsafe_value = value
|
|
225
|
-
tvar.unsafe_increment_version
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
unlock
|
|
229
|
-
|
|
230
|
-
true
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
def valid?
|
|
234
|
-
@read_log.each do |log_entry|
|
|
235
|
-
unless @write_log.has_key? log_entry.tvar
|
|
236
|
-
if log_entry.tvar.unsafe_version > log_entry.version
|
|
237
|
-
return false
|
|
238
|
-
end
|
|
196
|
+
@open_tvars.each do |tvar, entry|
|
|
197
|
+
if entry.modified
|
|
198
|
+
tvar.unsafe_value = entry.value
|
|
239
199
|
end
|
|
240
200
|
end
|
|
241
201
|
|
|
242
|
-
|
|
202
|
+
unlock
|
|
243
203
|
end
|
|
244
204
|
|
|
245
205
|
def unlock
|
|
246
|
-
@
|
|
206
|
+
@open_tvars.each_key do |tvar|
|
|
247
207
|
tvar.unsafe_lock.unlock
|
|
248
208
|
end
|
|
249
209
|
end
|
|
@@ -2,26 +2,64 @@ require 'concurrent/synchronization'
|
|
|
2
2
|
|
|
3
3
|
module Concurrent
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
# @!macro monotonic_get_time
|
|
6
|
+
#
|
|
7
|
+
# Returns the current time a tracked by the application monotonic clock.
|
|
8
|
+
#
|
|
9
|
+
# @param [Symbol] unit the time unit to be returned, can be either
|
|
10
|
+
# :float_second, :float_millisecond, :float_microsecond, :second,
|
|
11
|
+
# :millisecond, :microsecond, or :nanosecond default to :float_second.
|
|
12
|
+
#
|
|
13
|
+
# @return [Float] The current monotonic time since some unspecified
|
|
14
|
+
# starting point
|
|
15
|
+
#
|
|
16
|
+
# @!macro monotonic_clock_warning
|
|
17
|
+
if defined?(Process::CLOCK_MONOTONIC)
|
|
18
|
+
|
|
19
|
+
def monotonic_time(unit = :float_second)
|
|
20
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC, unit)
|
|
9
21
|
end
|
|
10
22
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
elsif Concurrent.on_jruby?
|
|
24
|
+
|
|
25
|
+
# @!visibility private
|
|
26
|
+
TIME_UNITS = Hash.new { |_hash, key| raise ArgumentError, "unexpected unit: #{key}" }.compare_by_identity
|
|
27
|
+
TIME_UNITS.merge!(
|
|
28
|
+
second: 1_000_000_000,
|
|
29
|
+
millisecond: 1_000_000,
|
|
30
|
+
microsecond: 1_000,
|
|
31
|
+
nanosecond: 1,
|
|
32
|
+
float_second: 1_000_000_000.0,
|
|
33
|
+
float_millisecond: 1_000_000.0,
|
|
34
|
+
float_microsecond: 1_000.0,
|
|
35
|
+
)
|
|
36
|
+
TIME_UNITS.freeze
|
|
37
|
+
private_constant :TIME_UNITS
|
|
38
|
+
|
|
39
|
+
def monotonic_time(unit = :float_second)
|
|
40
|
+
java.lang.System.nanoTime() / TIME_UNITS[unit]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
else
|
|
44
|
+
|
|
45
|
+
class_definition = Class.new(Synchronization::LockableObject) do
|
|
46
|
+
def initialize
|
|
47
|
+
@last_time = Time.now.to_f
|
|
48
|
+
@time_units = Hash.new { |_hash, key| raise ArgumentError, "unexpected unit: #{key}" }.compare_by_identity
|
|
49
|
+
@time_units.merge!(
|
|
50
|
+
second: [nil, true],
|
|
51
|
+
millisecond: [1_000, true],
|
|
52
|
+
microsecond: [1_000_000, true],
|
|
53
|
+
nanosecond: [1_000_000_000, true],
|
|
54
|
+
float_second: [nil, false],
|
|
55
|
+
float_millisecond: [1_000.0, false],
|
|
56
|
+
float_microsecond: [1_000_000.0, false],
|
|
57
|
+
)
|
|
58
|
+
super()
|
|
20
59
|
end
|
|
21
|
-
else
|
|
22
60
|
|
|
23
61
|
# @!visibility private
|
|
24
|
-
def get_time
|
|
62
|
+
def get_time(unit)
|
|
25
63
|
synchronize do
|
|
26
64
|
now = Time.now.to_f
|
|
27
65
|
if @last_time < now
|
|
@@ -29,30 +67,24 @@ module Concurrent
|
|
|
29
67
|
else # clock has moved back in time
|
|
30
68
|
@last_time += 0.000_001
|
|
31
69
|
end
|
|
70
|
+
scale, to_int = @time_units[unit]
|
|
71
|
+
now *= scale if scale
|
|
72
|
+
now = now.to_i if to_int
|
|
73
|
+
now
|
|
32
74
|
end
|
|
33
75
|
end
|
|
34
|
-
|
|
35
76
|
end
|
|
36
|
-
end
|
|
37
77
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
#
|
|
49
|
-
# @return [Float] The current monotonic time since some unspecified
|
|
50
|
-
# starting point
|
|
51
|
-
#
|
|
52
|
-
# @!macro monotonic_clock_warning
|
|
53
|
-
def monotonic_time
|
|
54
|
-
GLOBAL_MONOTONIC_CLOCK.get_time
|
|
78
|
+
# Clock that cannot be set and represents monotonic time since
|
|
79
|
+
# some unspecified starting point.
|
|
80
|
+
#
|
|
81
|
+
# @!visibility private
|
|
82
|
+
GLOBAL_MONOTONIC_CLOCK = class_definition.new
|
|
83
|
+
private_constant :GLOBAL_MONOTONIC_CLOCK
|
|
84
|
+
|
|
85
|
+
def monotonic_time(unit = :float_second)
|
|
86
|
+
GLOBAL_MONOTONIC_CLOCK.get_time(unit)
|
|
87
|
+
end
|
|
55
88
|
end
|
|
56
|
-
|
|
57
89
|
module_function :monotonic_time
|
|
58
90
|
end
|
|
@@ -79,47 +79,14 @@ module Concurrent
|
|
|
79
79
|
def compute_processor_count
|
|
80
80
|
if Concurrent.on_jruby?
|
|
81
81
|
java.lang.Runtime.getRuntime.availableProcessors
|
|
82
|
-
elsif Etc.respond_to?(:nprocessors) && (nprocessor = Etc.nprocessors rescue nil)
|
|
83
|
-
nprocessor
|
|
84
82
|
else
|
|
85
|
-
|
|
86
|
-
if os_name =~ /mingw|mswin/
|
|
87
|
-
require 'win32ole'
|
|
88
|
-
result = WIN32OLE.connect("winmgmts://").ExecQuery(
|
|
89
|
-
"select NumberOfLogicalProcessors from Win32_Processor")
|
|
90
|
-
result.to_enum.collect(&:NumberOfLogicalProcessors).reduce(:+)
|
|
91
|
-
elsif File.readable?("/proc/cpuinfo") && (cpuinfo_count = IO.read("/proc/cpuinfo").scan(/^processor/).size) > 0
|
|
92
|
-
cpuinfo_count
|
|
93
|
-
elsif File.executable?("/usr/bin/nproc")
|
|
94
|
-
IO.popen("/usr/bin/nproc --all", &:read).to_i
|
|
95
|
-
elsif File.executable?("/usr/bin/hwprefs")
|
|
96
|
-
IO.popen("/usr/bin/hwprefs thread_count", &:read).to_i
|
|
97
|
-
elsif File.executable?("/usr/sbin/psrinfo")
|
|
98
|
-
IO.popen("/usr/sbin/psrinfo", &:read).scan(/^.*on-*line/).size
|
|
99
|
-
elsif File.executable?("/usr/sbin/ioscan")
|
|
100
|
-
IO.popen("/usr/sbin/ioscan -kC processor", &:read).scan(/^.*processor/).size
|
|
101
|
-
elsif File.executable?("/usr/sbin/pmcycles")
|
|
102
|
-
IO.popen("/usr/sbin/pmcycles -m", &:read).count("\n")
|
|
103
|
-
elsif File.executable?("/usr/sbin/lsdev")
|
|
104
|
-
IO.popen("/usr/sbin/lsdev -Cc processor -S 1", &:read).count("\n")
|
|
105
|
-
elsif File.executable?("/usr/sbin/sysconf") and os_name =~ /irix/i
|
|
106
|
-
IO.popen("/usr/sbin/sysconf NPROC_ONLN", &:read).to_i
|
|
107
|
-
elsif File.executable?("/usr/sbin/sysctl")
|
|
108
|
-
IO.popen("/usr/sbin/sysctl -n hw.ncpu", &:read).to_i
|
|
109
|
-
elsif File.executable?("/sbin/sysctl")
|
|
110
|
-
IO.popen("/sbin/sysctl -n hw.ncpu", &:read).to_i
|
|
111
|
-
else
|
|
112
|
-
# TODO (pitr-ch 05-Nov-2016): warn about failures
|
|
113
|
-
1
|
|
114
|
-
end
|
|
83
|
+
Etc.nprocessors
|
|
115
84
|
end
|
|
116
|
-
rescue
|
|
117
|
-
return 1
|
|
118
85
|
end
|
|
119
86
|
|
|
120
87
|
def compute_physical_processor_count
|
|
121
88
|
ppc = case RbConfig::CONFIG["target_os"]
|
|
122
|
-
when /
|
|
89
|
+
when /darwin\d\d/
|
|
123
90
|
IO.popen("/usr/sbin/sysctl -n hw.physicalcpu", &:read).to_i
|
|
124
91
|
when /linux/
|
|
125
92
|
cores = {} # unique physical ID / core ID combinations
|
metadata
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: concurrent-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jerry D'Antonio
|
|
8
8
|
- Petr Chalupa
|
|
9
9
|
- The Ruby Concurrency Team
|
|
10
|
-
autorequire:
|
|
10
|
+
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date:
|
|
13
|
+
date: 2022-03-22 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.
|
|
@@ -79,6 +79,7 @@ files:
|
|
|
79
79
|
- lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb
|
|
80
80
|
- lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb
|
|
81
81
|
- lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb
|
|
82
|
+
- lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb
|
|
82
83
|
- lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb
|
|
83
84
|
- lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb
|
|
84
85
|
- lib/concurrent-ruby/concurrent/concern/deprecation.rb
|
|
@@ -169,7 +170,7 @@ licenses:
|
|
|
169
170
|
metadata:
|
|
170
171
|
source_code_uri: https://github.com/ruby-concurrency/concurrent-ruby
|
|
171
172
|
changelog_uri: https://github.com/ruby-concurrency/concurrent-ruby/blob/master/CHANGELOG.md
|
|
172
|
-
post_install_message:
|
|
173
|
+
post_install_message:
|
|
173
174
|
rdoc_options: []
|
|
174
175
|
require_paths:
|
|
175
176
|
- lib/concurrent-ruby
|
|
@@ -177,15 +178,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
177
178
|
requirements:
|
|
178
179
|
- - ">="
|
|
179
180
|
- !ruby/object:Gem::Version
|
|
180
|
-
version:
|
|
181
|
+
version: '2.2'
|
|
181
182
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
182
183
|
requirements:
|
|
183
184
|
- - ">="
|
|
184
185
|
- !ruby/object:Gem::Version
|
|
185
186
|
version: '0'
|
|
186
187
|
requirements: []
|
|
187
|
-
rubygems_version: 3.
|
|
188
|
-
signing_key:
|
|
188
|
+
rubygems_version: 3.3.4
|
|
189
|
+
signing_key:
|
|
189
190
|
specification_version: 4
|
|
190
191
|
summary: Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell,
|
|
191
192
|
F#, C#, Java, and classic concurrency patterns.
|