concurrent-ruby 1.1.5 → 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 +65 -1
- data/Gemfile +6 -10
- data/{LICENSE.md → LICENSE.txt} +18 -20
- data/README.md +46 -23
- data/Rakefile +46 -44
- 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 → concurrent-ruby/concurrent}/agent.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/array.rb +6 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +10 -20
- data/lib/{concurrent → concurrent-ruby/concurrent}/atom.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/abstract_thread_local_var.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_boolean.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_fixnum.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_markable_reference.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_reference.rb +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/count_down_latch.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/cyclic_barrier.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/event.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_count_down_latch.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_thread_local_var.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_boolean.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_fixnum.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_count_down_latch.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_semaphore.rb +18 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/read_write_lock.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/reentrant_read_write_lock.rb +4 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/ruby_thread_local_var.rb +60 -40
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +26 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/thread_local_var.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/mutex_atomic.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/numeric_cas_wrapper.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomics.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_write_observer_set.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/lock_free_stack.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/mri_map_backend.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb +0 -0
- data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/non_concurrent_priority_queue.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb +11 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/deprecation.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/dereferenceable.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/logging.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/obligation.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/observable.rb +0 -0
- data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/configuration.rb +13 -9
- data/lib/{concurrent → concurrent-ruby/concurrent}/constants.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/dataflow.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/delay.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/errors.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/exchanger.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/abstract_executor_service.rb +33 -36
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/cached_thread_pool.rb +4 -4
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/executor_service.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/fixed_thread_pool.rb +29 -15
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/immediate_executor.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/indirect_immediate_executor.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_executor_service.rb +19 -7
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_single_thread_executor.rb +4 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_thread_pool_executor.rb +19 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +10 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_single_thread_executor.rb +0 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_thread_pool_executor.rb +46 -42
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +5 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serial_executor_service.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/simple_executor_service.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/single_thread_executor.rb +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/thread_pool_executor.rb +2 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/timer_set.rb +0 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/executors.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/future.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/hash.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/immutable_struct.rb +9 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/ivar.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/map.rb +14 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/maybe.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/mutable_struct.rb +12 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/mvar.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/options.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/promise.rb +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/promises.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/re_include.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +29 -16
- data/lib/{concurrent → concurrent-ruby/concurrent}/set.rb +19 -11
- data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +11 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_struct.rb +11 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +3 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mri_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mutex_lockable_object.rb +12 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_lockable_object.rb +6 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/truffleruby_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/volatile.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/synchronized_delegator.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/adder.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/cheap_lockable.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/data_structures.rb +26 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/power_of_two_tuple.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/striped64.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/volatile.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/xor_shift_random.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +11 -34
- data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +19 -56
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +0 -0
- data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_extension_loader.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_integer.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/processor_counter.rb +5 -33
- data/lib/concurrent-ruby/concurrent/version.rb +3 -0
- data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
- data/lib/{concurrent.rb → concurrent-ruby/concurrent.rb} +0 -0
- metadata +132 -132
- data/lib/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent/utility/at_exit.rb +0 -97
- data/lib/concurrent/utility/monotonic_time.rb +0 -58
- data/lib/concurrent/version.rb +0 -3
- data/lib/concurrent-ruby.rb +0 -1
@@ -23,6 +23,9 @@ module Concurrent
|
|
23
23
|
# @!macro thread_pool_executor_constant_default_thread_timeout
|
24
24
|
DEFAULT_THREAD_IDLETIMEOUT = 60
|
25
25
|
|
26
|
+
# @!macro thread_pool_executor_constant_default_synchronous
|
27
|
+
DEFAULT_SYNCHRONOUS = false
|
28
|
+
|
26
29
|
# @!macro thread_pool_executor_attr_reader_max_length
|
27
30
|
attr_reader :max_length
|
28
31
|
|
@@ -35,6 +38,9 @@ module Concurrent
|
|
35
38
|
# @!macro thread_pool_executor_attr_reader_max_queue
|
36
39
|
attr_reader :max_queue
|
37
40
|
|
41
|
+
# @!macro thread_pool_executor_attr_reader_synchronous
|
42
|
+
attr_reader :synchronous
|
43
|
+
|
38
44
|
# @!macro thread_pool_executor_method_initialize
|
39
45
|
def initialize(opts = {})
|
40
46
|
super(opts)
|
@@ -87,13 +93,8 @@ module Concurrent
|
|
87
93
|
end
|
88
94
|
|
89
95
|
# @!visibility private
|
90
|
-
def ready_worker(worker)
|
91
|
-
synchronize { ns_ready_worker worker }
|
92
|
-
end
|
93
|
-
|
94
|
-
# @!visibility private
|
95
|
-
def worker_not_old_enough(worker)
|
96
|
-
synchronize { ns_worker_not_old_enough worker }
|
96
|
+
def ready_worker(worker, last_message)
|
97
|
+
synchronize { ns_ready_worker worker, last_message }
|
97
98
|
end
|
98
99
|
|
99
100
|
# @!visibility private
|
@@ -106,6 +107,11 @@ module Concurrent
|
|
106
107
|
synchronize { @completed_task_count += 1 }
|
107
108
|
end
|
108
109
|
|
110
|
+
# @!macro thread_pool_executor_method_prune_pool
|
111
|
+
def prune_pool
|
112
|
+
synchronize { ns_prune_pool }
|
113
|
+
end
|
114
|
+
|
109
115
|
private
|
110
116
|
|
111
117
|
# @!visibility private
|
@@ -114,16 +120,16 @@ module Concurrent
|
|
114
120
|
@max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i
|
115
121
|
@idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i
|
116
122
|
@max_queue = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i
|
123
|
+
@synchronous = opts.fetch(:synchronous, DEFAULT_SYNCHRONOUS)
|
117
124
|
@fallback_policy = opts.fetch(:fallback_policy, :abort)
|
118
|
-
raise ArgumentError.new("#{@fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICIES.include?(@fallback_policy)
|
119
125
|
|
126
|
+
raise ArgumentError.new("`synchronous` cannot be set unless `max_queue` is 0") if @synchronous && @max_queue > 0
|
127
|
+
raise ArgumentError.new("#{@fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICIES.include?(@fallback_policy)
|
120
128
|
raise ArgumentError.new("`max_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if @max_length < DEFAULT_MIN_POOL_SIZE
|
121
129
|
raise ArgumentError.new("`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}") if @max_length > DEFAULT_MAX_POOL_SIZE
|
122
130
|
raise ArgumentError.new("`min_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if @min_length < DEFAULT_MIN_POOL_SIZE
|
123
131
|
raise ArgumentError.new("`min_threads` cannot be more than `max_threads`") if min_length > max_length
|
124
132
|
|
125
|
-
self.auto_terminate = opts.fetch(:auto_terminate, true)
|
126
|
-
|
127
133
|
@pool = [] # all workers
|
128
134
|
@ready = [] # used as a stash (most idle worker is at the start)
|
129
135
|
@queue = [] # used as queue
|
@@ -131,6 +137,7 @@ module Concurrent
|
|
131
137
|
@scheduled_task_count = 0
|
132
138
|
@completed_task_count = 0
|
133
139
|
@largest_length = 0
|
140
|
+
@workers_counter = 0
|
134
141
|
@ruby_pid = $$ # detects if Ruby has forked
|
135
142
|
|
136
143
|
@gc_interval = opts.fetch(:gc_interval, @idletime / 2.0).to_i # undocumented
|
@@ -149,10 +156,11 @@ module Concurrent
|
|
149
156
|
if ns_assign_worker(*args, &task) || ns_enqueue(*args, &task)
|
150
157
|
@scheduled_task_count += 1
|
151
158
|
else
|
152
|
-
|
159
|
+
return fallback_action(*args, &task)
|
153
160
|
end
|
154
161
|
|
155
162
|
ns_prune_pool if @next_gc_time < Concurrent.monotonic_time
|
163
|
+
nil
|
156
164
|
end
|
157
165
|
|
158
166
|
# @!visibility private
|
@@ -185,7 +193,7 @@ module Concurrent
|
|
185
193
|
# @!visibility private
|
186
194
|
def ns_assign_worker(*args, &task)
|
187
195
|
# keep growing if the pool is not at the minimum yet
|
188
|
-
worker = (@ready.pop if @pool.size >= @min_length) || ns_add_busy_worker
|
196
|
+
worker, _ = (@ready.pop if @pool.size >= @min_length) || ns_add_busy_worker
|
189
197
|
if worker
|
190
198
|
worker << [task, args]
|
191
199
|
true
|
@@ -202,6 +210,8 @@ module Concurrent
|
|
202
210
|
#
|
203
211
|
# @!visibility private
|
204
212
|
def ns_enqueue(*args, &task)
|
213
|
+
return false if @synchronous
|
214
|
+
|
205
215
|
if !ns_limited_queue? || @queue.size < @max_queue
|
206
216
|
@queue << [task, args]
|
207
217
|
true
|
@@ -214,7 +224,7 @@ module Concurrent
|
|
214
224
|
def ns_worker_died(worker)
|
215
225
|
ns_remove_busy_worker worker
|
216
226
|
replacement_worker = ns_add_busy_worker
|
217
|
-
ns_ready_worker replacement_worker, false if replacement_worker
|
227
|
+
ns_ready_worker replacement_worker, Concurrent.monotonic_time, false if replacement_worker
|
218
228
|
end
|
219
229
|
|
220
230
|
# creates new worker which has to receive work to do after it's added
|
@@ -224,7 +234,8 @@ module Concurrent
|
|
224
234
|
def ns_add_busy_worker
|
225
235
|
return if @pool.size >= @max_length
|
226
236
|
|
227
|
-
@
|
237
|
+
@workers_counter += 1
|
238
|
+
@pool << (worker = Worker.new(self, @workers_counter))
|
228
239
|
@largest_length = @pool.length if @pool.length > @largest_length
|
229
240
|
worker
|
230
241
|
end
|
@@ -232,29 +243,21 @@ module Concurrent
|
|
232
243
|
# handle ready worker, giving it new job or assigning back to @ready
|
233
244
|
#
|
234
245
|
# @!visibility private
|
235
|
-
def ns_ready_worker(worker, success = true)
|
246
|
+
def ns_ready_worker(worker, last_message, success = true)
|
236
247
|
task_and_args = @queue.shift
|
237
248
|
if task_and_args
|
238
249
|
worker << task_and_args
|
239
250
|
else
|
240
251
|
# stop workers when !running?, do not return them to @ready
|
241
252
|
if running?
|
242
|
-
|
253
|
+
raise unless last_message
|
254
|
+
@ready.push([worker, last_message])
|
243
255
|
else
|
244
256
|
worker.stop
|
245
257
|
end
|
246
258
|
end
|
247
259
|
end
|
248
260
|
|
249
|
-
# returns back worker to @ready which was not idle for enough time
|
250
|
-
#
|
251
|
-
# @!visibility private
|
252
|
-
def ns_worker_not_old_enough(worker)
|
253
|
-
# let's put workers coming from idle_test back to the start (as the oldest worker)
|
254
|
-
@ready.unshift(worker)
|
255
|
-
true
|
256
|
-
end
|
257
|
-
|
258
261
|
# removes a worker which is not in not tracked in @ready
|
259
262
|
#
|
260
263
|
# @!visibility private
|
@@ -268,10 +271,17 @@ module Concurrent
|
|
268
271
|
#
|
269
272
|
# @!visibility private
|
270
273
|
def ns_prune_pool
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
274
|
+
now = Concurrent.monotonic_time
|
275
|
+
stopped_workers = 0
|
276
|
+
while !@ready.empty? && (@pool.size - stopped_workers > @min_length)
|
277
|
+
worker, last_message = @ready.first
|
278
|
+
if now - last_message > self.idletime
|
279
|
+
stopped_workers += 1
|
280
|
+
@ready.shift
|
281
|
+
worker << :stop
|
282
|
+
else break
|
283
|
+
end
|
284
|
+
end
|
275
285
|
|
276
286
|
@next_gc_time = Concurrent.monotonic_time + @gc_interval
|
277
287
|
end
|
@@ -284,6 +294,7 @@ module Concurrent
|
|
284
294
|
@scheduled_task_count = 0
|
285
295
|
@completed_task_count = 0
|
286
296
|
@largest_length = 0
|
297
|
+
@workers_counter = 0
|
287
298
|
@ruby_pid = $$
|
288
299
|
end
|
289
300
|
end
|
@@ -292,11 +303,15 @@ module Concurrent
|
|
292
303
|
class Worker
|
293
304
|
include Concern::Logging
|
294
305
|
|
295
|
-
def initialize(pool)
|
306
|
+
def initialize(pool, id)
|
296
307
|
# instance variables accessed only under pool's lock so no need to sync here again
|
297
308
|
@queue = Queue.new
|
298
309
|
@pool = pool
|
299
310
|
@thread = create_worker @queue, pool, pool.idletime
|
311
|
+
|
312
|
+
if @thread.respond_to?(:name=)
|
313
|
+
@thread.name = [pool.name, 'worker', id].compact.join('-')
|
314
|
+
end
|
300
315
|
end
|
301
316
|
|
302
317
|
def <<(message)
|
@@ -315,19 +330,10 @@ module Concurrent
|
|
315
330
|
|
316
331
|
def create_worker(queue, pool, idletime)
|
317
332
|
Thread.new(queue, pool, idletime) do |my_queue, my_pool, my_idletime|
|
318
|
-
last_message = Concurrent.monotonic_time
|
319
333
|
catch(:stop) do
|
320
334
|
loop do
|
321
335
|
|
322
336
|
case message = my_queue.pop
|
323
|
-
when :idle_test
|
324
|
-
if (Concurrent.monotonic_time - last_message) > my_idletime
|
325
|
-
my_pool.remove_busy_worker(self)
|
326
|
-
throw :stop
|
327
|
-
else
|
328
|
-
my_pool.worker_not_old_enough(self)
|
329
|
-
end
|
330
|
-
|
331
337
|
when :stop
|
332
338
|
my_pool.remove_busy_worker(self)
|
333
339
|
throw :stop
|
@@ -335,9 +341,7 @@ module Concurrent
|
|
335
341
|
else
|
336
342
|
task, args = message
|
337
343
|
run_task my_pool, task, args
|
338
|
-
|
339
|
-
|
340
|
-
my_pool.ready_worker(self)
|
344
|
+
my_pool.ready_worker(self, Concurrent.monotonic_time)
|
341
345
|
end
|
342
346
|
end
|
343
347
|
end
|
@@ -16,10 +16,10 @@ module Concurrent
|
|
16
16
|
|
17
17
|
# @return [Array]
|
18
18
|
def execute(*args)
|
19
|
-
|
20
|
-
|
21
|
-
value = reason = nil
|
19
|
+
success = true
|
20
|
+
value = reason = nil
|
22
21
|
|
22
|
+
synchronize do
|
23
23
|
begin
|
24
24
|
value = @task.call(*args)
|
25
25
|
success = true
|
@@ -27,9 +27,9 @@ module Concurrent
|
|
27
27
|
reason = ex
|
28
28
|
success = false
|
29
29
|
end
|
30
|
-
|
31
|
-
[success, value, reason]
|
32
30
|
end
|
31
|
+
|
32
|
+
[success, value, reason]
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
File without changes
|
File without changes
|
data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb
RENAMED
File without changes
|
@@ -73,7 +73,8 @@ module Concurrent
|
|
73
73
|
# @option opts [Symbol] :fallback_policy (:abort) the policy for handling new
|
74
74
|
# tasks that are received when the queue size has reached
|
75
75
|
# `max_queue` or the executor has shut down
|
76
|
-
#
|
76
|
+
# @option opts [Boolean] :synchronous (DEFAULT_SYNCHRONOUS) whether or not a value of 0
|
77
|
+
# for :max_queue means the queue must perform direct hand-off rather than unbounded.
|
77
78
|
# @raise [ArgumentError] if `:max_threads` is less than one
|
78
79
|
# @raise [ArgumentError] if `:min_threads` is less than zero
|
79
80
|
# @raise [ArgumentError] if `:fallback_policy` is not one of the values specified
|
File without changes
|
File without changes
|
@@ -10,7 +10,7 @@ module Concurrent
|
|
10
10
|
# or writing at a time. This includes iteration methods like `#each`,
|
11
11
|
# which takes the lock repeatedly when reading an item.
|
12
12
|
#
|
13
|
-
# @see http://ruby-doc.org/core
|
13
|
+
# @see http://ruby-doc.org/core/Hash.html Ruby standard library `Hash`
|
14
14
|
|
15
15
|
# @!macro internal_implementation_note
|
16
16
|
HashImplementation = case
|
@@ -5,7 +5,7 @@ module Concurrent
|
|
5
5
|
|
6
6
|
# A thread-safe, immutable variation of Ruby's standard `Struct`.
|
7
7
|
#
|
8
|
-
# @see http://ruby-doc.org/core
|
8
|
+
# @see http://ruby-doc.org/core/Struct.html Ruby standard library `Struct`
|
9
9
|
module ImmutableStruct
|
10
10
|
include Synchronization::AbstractStruct
|
11
11
|
|
@@ -70,6 +70,14 @@ module Concurrent
|
|
70
70
|
ns_select(&block)
|
71
71
|
end
|
72
72
|
|
73
|
+
private
|
74
|
+
|
75
|
+
# @!visibility private
|
76
|
+
def initialize_copy(original)
|
77
|
+
super(original)
|
78
|
+
ns_initialize_copy
|
79
|
+
end
|
80
|
+
|
73
81
|
# @!macro struct_new
|
74
82
|
def self.new(*args, &block)
|
75
83
|
clazz_name = nil
|
File without changes
|
@@ -15,7 +15,10 @@ module Concurrent
|
|
15
15
|
when Concurrent.on_cruby?
|
16
16
|
require 'concurrent/collection/map/mri_map_backend'
|
17
17
|
MriMapBackend
|
18
|
-
when Concurrent.
|
18
|
+
when Concurrent.on_truffleruby? && defined?(::TruffleRuby::ConcurrentMap)
|
19
|
+
require 'concurrent/collection/map/truffleruby_map_backend'
|
20
|
+
TruffleRubyMapBackend
|
21
|
+
when Concurrent.on_truffleruby? || Concurrent.on_rbx?
|
19
22
|
require 'concurrent/collection/map/atomic_reference_map_backend'
|
20
23
|
AtomicReferenceMapBackend
|
21
24
|
else
|
@@ -114,7 +117,7 @@ module Concurrent
|
|
114
117
|
# @return [true, false] true if deleted
|
115
118
|
# @!macro map.atomic_method
|
116
119
|
|
117
|
-
|
120
|
+
#
|
118
121
|
def initialize(options = nil, &block)
|
119
122
|
if options.kind_of?(::Hash)
|
120
123
|
validate_options_hash!(options)
|
@@ -143,8 +146,15 @@ module Concurrent
|
|
143
146
|
end
|
144
147
|
end
|
145
148
|
|
149
|
+
# Set a value with key
|
150
|
+
# @param [Object] key
|
151
|
+
# @param [Object] value
|
152
|
+
# @return [Object] the new value
|
153
|
+
def []=(key, value)
|
154
|
+
super
|
155
|
+
end
|
156
|
+
|
146
157
|
alias_method :get, :[]
|
147
|
-
# TODO (pitr-ch 30-Oct-2018): doc
|
148
158
|
alias_method :put, :[]=
|
149
159
|
|
150
160
|
# Get a value with key, or default_value when key is absent,
|
@@ -197,7 +207,7 @@ module Concurrent
|
|
197
207
|
# Insert value into map with key if key is absent in one atomic step.
|
198
208
|
# @param [Object] key
|
199
209
|
# @param [Object] value
|
200
|
-
# @return [Object, nil] the value or nil when
|
210
|
+
# @return [Object, nil] the previous value when key was present or nil when there was no key
|
201
211
|
def put_if_absent(key, value)
|
202
212
|
computed = false
|
203
213
|
result = compute_if_absent(key) do
|
@@ -271,7 +281,6 @@ module Concurrent
|
|
271
281
|
each_pair { |k, v| return k if v == value }
|
272
282
|
nil
|
273
283
|
end unless method_defined?(:key)
|
274
|
-
alias_method :index, :key if RUBY_VERSION < '1.9'
|
275
284
|
|
276
285
|
# Is map empty?
|
277
286
|
# @return [true, false]
|
File without changes
|
@@ -6,7 +6,7 @@ module Concurrent
|
|
6
6
|
# An thread-safe variation of Ruby's standard `Struct`. Values can be set at
|
7
7
|
# construction or safely changed at any time during the object's lifecycle.
|
8
8
|
#
|
9
|
-
# @see http://ruby-doc.org/core
|
9
|
+
# @see http://ruby-doc.org/core/Struct.html Ruby standard library `Struct`
|
10
10
|
module MutableStruct
|
11
11
|
include Synchronization::AbstractStruct
|
12
12
|
|
@@ -40,7 +40,7 @@ module Concurrent
|
|
40
40
|
# struct. Unset parameters default to nil. Passing more parameters than number of attributes
|
41
41
|
# will raise an `ArgumentError`.
|
42
42
|
#
|
43
|
-
# @see http://ruby-doc.org/core
|
43
|
+
# @see http://ruby-doc.org/core/Struct.html#method-c-new Ruby standard library `Struct#new`
|
44
44
|
|
45
45
|
# @!macro struct_values
|
46
46
|
#
|
@@ -196,6 +196,16 @@ module Concurrent
|
|
196
196
|
raise NameError.new("no member '#{member}' in struct")
|
197
197
|
end
|
198
198
|
|
199
|
+
private
|
200
|
+
|
201
|
+
# @!visibility private
|
202
|
+
def initialize_copy(original)
|
203
|
+
synchronize do
|
204
|
+
super(original)
|
205
|
+
ns_initialize_copy
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
199
209
|
# @!macro struct_new
|
200
210
|
def self.new(*args, &block)
|
201
211
|
clazz_name = nil
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -58,29 +58,42 @@ module Concurrent
|
|
58
58
|
# @example Basic usage
|
59
59
|
#
|
60
60
|
# require 'concurrent'
|
61
|
-
# require '
|
62
|
-
# require 'open-uri'
|
61
|
+
# require 'csv'
|
62
|
+
# require 'open-uri'
|
63
63
|
#
|
64
64
|
# class Ticker
|
65
|
-
# def get_year_end_closing(symbol, year)
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
65
|
+
# def get_year_end_closing(symbol, year, api_key)
|
66
|
+
# uri = "https://www.alphavantage.co/query?function=TIME_SERIES_MONTHLY&symbol=#{symbol}&apikey=#{api_key}&datatype=csv"
|
67
|
+
# data = []
|
68
|
+
# csv = URI.parse(uri).read
|
69
|
+
# if csv.include?('call frequency')
|
70
|
+
# return :rate_limit_exceeded
|
71
|
+
# end
|
72
|
+
# CSV.parse(csv, headers: true) do |row|
|
73
|
+
# data << row['close'].to_f if row['timestamp'].include?(year.to_s)
|
74
|
+
# end
|
75
|
+
# year_end = data.first
|
76
|
+
# year_end
|
77
|
+
# rescue => e
|
78
|
+
# p e
|
79
|
+
# end
|
70
80
|
# end
|
71
81
|
#
|
82
|
+
# api_key = ENV['ALPHAVANTAGE_KEY']
|
83
|
+
# abort(error_message) unless api_key
|
84
|
+
#
|
72
85
|
# # Future
|
73
|
-
# price = Concurrent::Future.execute{ Ticker.new.get_year_end_closing('TWTR', 2013) }
|
86
|
+
# price = Concurrent::Future.execute{ Ticker.new.get_year_end_closing('TWTR', 2013, api_key) }
|
74
87
|
# price.state #=> :pending
|
75
|
-
#
|
76
|
-
# price.value #=>
|
77
|
-
# price.state #=> :fulfilled
|
88
|
+
# price.pending? #=> true
|
89
|
+
# price.value(0) #=> nil (does not block)
|
78
90
|
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
91
|
+
# sleep(1) # do other stuff
|
92
|
+
#
|
93
|
+
# price.value #=> 63.65 (after blocking if necessary)
|
94
|
+
# price.state #=> :fulfilled
|
95
|
+
# price.fulfilled? #=> true
|
96
|
+
# price.value #=> 63.65
|
84
97
|
#
|
85
98
|
# @example Successful task execution
|
86
99
|
#
|
@@ -11,21 +11,27 @@ module Concurrent
|
|
11
11
|
# or writing at a time. This includes iteration methods like `#each`.
|
12
12
|
#
|
13
13
|
# @note `a += b` is **not** a **thread-safe** operation on
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
14
|
+
# `Concurrent::Set`. It reads Set `a`, then it creates new `Concurrent::Set`
|
15
|
+
# which is union of `a` and `b`, then it writes the union to `a`.
|
16
|
+
# The read and write are independent operations they do not form a single atomic
|
17
|
+
# operation therefore when two `+=` operations are executed concurrently updates
|
18
|
+
# may be lost. Use `#merge` instead.
|
19
19
|
#
|
20
20
|
# @see http://ruby-doc.org/stdlib-2.4.0/libdoc/set/rdoc/Set.html Ruby standard library `Set`
|
21
21
|
|
22
|
-
|
23
22
|
# @!macro internal_implementation_note
|
24
23
|
SetImplementation = case
|
25
24
|
when Concurrent.on_cruby?
|
26
|
-
#
|
27
|
-
#
|
28
|
-
|
25
|
+
# The CRuby implementation of Set is written in Ruby itself and is
|
26
|
+
# not thread safe for certain methods.
|
27
|
+
require 'monitor'
|
28
|
+
require 'concurrent/thread_safe/util/data_structures'
|
29
|
+
|
30
|
+
class CRubySet < ::Set
|
31
|
+
end
|
32
|
+
|
33
|
+
ThreadSafe::Util.make_synchronized_on_cruby CRubySet
|
34
|
+
CRubySet
|
29
35
|
|
30
36
|
when Concurrent.on_jruby?
|
31
37
|
require 'jruby/synchronized'
|
@@ -33,6 +39,7 @@ module Concurrent
|
|
33
39
|
class JRubySet < ::Set
|
34
40
|
include JRuby::Synchronized
|
35
41
|
end
|
42
|
+
|
36
43
|
JRubySet
|
37
44
|
|
38
45
|
when Concurrent.on_rbx?
|
@@ -41,7 +48,8 @@ module Concurrent
|
|
41
48
|
|
42
49
|
class RbxSet < ::Set
|
43
50
|
end
|
44
|
-
|
51
|
+
|
52
|
+
ThreadSafe::Util.make_synchronized_on_rbx RbxSet
|
45
53
|
RbxSet
|
46
54
|
|
47
55
|
when Concurrent.on_truffleruby?
|
@@ -50,7 +58,7 @@ module Concurrent
|
|
50
58
|
class TruffleRubySet < ::Set
|
51
59
|
end
|
52
60
|
|
53
|
-
ThreadSafe::Util.make_synchronized_on_truffleruby
|
61
|
+
ThreadSafe::Util.make_synchronized_on_truffleruby TruffleRubySet
|
54
62
|
TruffleRubySet
|
55
63
|
|
56
64
|
else
|
@@ -9,7 +9,7 @@ module Concurrent
|
|
9
9
|
# or any time thereafter. Attempting to assign a value to a member
|
10
10
|
# that has already been set will result in a `Concurrent::ImmutabilityError`.
|
11
11
|
#
|
12
|
-
# @see http://ruby-doc.org/core
|
12
|
+
# @see http://ruby-doc.org/core/Struct.html Ruby standard library `Struct`
|
13
13
|
# @see http://en.wikipedia.org/wiki/Final_(Java) Java `final` keyword
|
14
14
|
module SettableStruct
|
15
15
|
include Synchronization::AbstractStruct
|
@@ -91,6 +91,16 @@ module Concurrent
|
|
91
91
|
raise NameError.new("no member '#{member}' in struct")
|
92
92
|
end
|
93
93
|
|
94
|
+
private
|
95
|
+
|
96
|
+
# @!visibility private
|
97
|
+
def initialize_copy(original)
|
98
|
+
synchronize do
|
99
|
+
super(original)
|
100
|
+
ns_initialize_copy
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
94
104
|
# @!macro struct_new
|
95
105
|
def self.new(*args, &block)
|
96
106
|
clazz_name = nil
|
data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb
RENAMED
File without changes
|
File without changes
|
@@ -115,6 +115,17 @@ module Concurrent
|
|
115
115
|
self.class.new(*self.to_h.merge(other, &block).values)
|
116
116
|
end
|
117
117
|
|
118
|
+
# @!visibility private
|
119
|
+
def ns_initialize_copy
|
120
|
+
@values = @values.map do |val|
|
121
|
+
begin
|
122
|
+
val.clone
|
123
|
+
rescue TypeError
|
124
|
+
val
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
118
129
|
# @!visibility private
|
119
130
|
def pr_underscore(clazz)
|
120
131
|
word = clazz.to_s.dup # dup string to workaround JRuby 9.2.0.0 bug https://github.com/jruby/jruby/issues/5229
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -4,9 +4,7 @@ module Concurrent
|
|
4
4
|
# @!visibility private
|
5
5
|
# @!macro internal_implementation_note
|
6
6
|
LockableObjectImplementation = case
|
7
|
-
when Concurrent.on_cruby?
|
8
|
-
MonitorLockableObject
|
9
|
-
when Concurrent.on_cruby? && Concurrent.ruby_version(:>, 1, 9, 3)
|
7
|
+
when Concurrent.on_cruby?
|
10
8
|
MutexLockableObject
|
11
9
|
when Concurrent.on_jruby?
|
12
10
|
JRubyLockableObject
|
@@ -26,8 +24,8 @@ module Concurrent
|
|
26
24
|
# the classes using it. Use {Synchronization::Object} not this abstract class.
|
27
25
|
#
|
28
26
|
# @note this object does not support usage together with
|
29
|
-
# [`Thread#wakeup`](http://ruby-doc.org/core
|
30
|
-
# and [`Thread#raise`](http://ruby-doc.org/core
|
27
|
+
# [`Thread#wakeup`](http://ruby-doc.org/core/Thread.html#method-i-wakeup)
|
28
|
+
# and [`Thread#raise`](http://ruby-doc.org/core/Thread.html#method-i-raise).
|
31
29
|
# `Thread#sleep` and `Thread#wakeup` will work as expected but mixing `Synchronization::Object#wait` and
|
32
30
|
# `Thread#wakeup` will not work on all platforms.
|
33
31
|
#
|
File without changes
|