o-concurrent-ruby 1.1.11
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 +7 -0
- data/CHANGELOG.md +542 -0
- data/Gemfile +37 -0
- data/LICENSE.txt +21 -0
- data/README.md +404 -0
- data/Rakefile +307 -0
- data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +189 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
- data/lib/concurrent-ruby/concurrent/agent.rb +587 -0
- data/lib/concurrent-ruby/concurrent/array.rb +66 -0
- data/lib/concurrent-ruby/concurrent/async.rb +449 -0
- data/lib/concurrent-ruby/concurrent/atom.rb +222 -0
- data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +66 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +126 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +143 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +205 -0
- data/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb +100 -0
- data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +128 -0
- data/lib/concurrent-ruby/concurrent/atomic/event.rb +109 -0
- data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +42 -0
- data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +37 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +44 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +131 -0
- data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +254 -0
- data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +377 -0
- data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +181 -0
- data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +166 -0
- data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +104 -0
- data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +56 -0
- data/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
- data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
- data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
- data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +111 -0
- data/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
- data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
- data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
- data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +66 -0
- data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
- data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +82 -0
- data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
- data/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
- data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +160 -0
- data/lib/concurrent-ruby/concurrent/concern/deprecation.rb +34 -0
- data/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb +73 -0
- data/lib/concurrent-ruby/concurrent/concern/logging.rb +32 -0
- data/lib/concurrent-ruby/concurrent/concern/obligation.rb +220 -0
- data/lib/concurrent-ruby/concurrent/concern/observable.rb +110 -0
- data/lib/concurrent-ruby/concurrent/configuration.rb +188 -0
- data/lib/concurrent-ruby/concurrent/constants.rb +8 -0
- data/lib/concurrent-ruby/concurrent/dataflow.rb +81 -0
- data/lib/concurrent-ruby/concurrent/delay.rb +199 -0
- data/lib/concurrent-ruby/concurrent/errors.rb +69 -0
- data/lib/concurrent-ruby/concurrent/exchanger.rb +352 -0
- data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +131 -0
- data/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb +62 -0
- data/lib/concurrent-ruby/concurrent/executor/executor_service.rb +185 -0
- data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +220 -0
- data/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb +66 -0
- data/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb +44 -0
- data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +103 -0
- data/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb +30 -0
- data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +140 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +82 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb +21 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +368 -0
- data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +35 -0
- data/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb +34 -0
- data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +107 -0
- data/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb +28 -0
- data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +100 -0
- data/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb +57 -0
- data/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb +88 -0
- data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +172 -0
- data/lib/concurrent-ruby/concurrent/executors.rb +20 -0
- data/lib/concurrent-ruby/concurrent/future.rb +141 -0
- data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
- data/lib/concurrent-ruby/concurrent/immutable_struct.rb +101 -0
- data/lib/concurrent-ruby/concurrent/ivar.rb +207 -0
- data/lib/concurrent-ruby/concurrent/map.rb +346 -0
- data/lib/concurrent-ruby/concurrent/maybe.rb +229 -0
- data/lib/concurrent-ruby/concurrent/mutable_struct.rb +239 -0
- data/lib/concurrent-ruby/concurrent/mvar.rb +242 -0
- data/lib/concurrent-ruby/concurrent/options.rb +42 -0
- data/lib/concurrent-ruby/concurrent/promise.rb +580 -0
- data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
- data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
- data/lib/concurrent-ruby/concurrent/scheduled_task.rb +331 -0
- data/lib/concurrent-ruby/concurrent/set.rb +74 -0
- data/lib/concurrent-ruby/concurrent/settable_struct.rb +139 -0
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +98 -0
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +24 -0
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb +171 -0
- data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +60 -0
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +13 -0
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +45 -0
- data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +36 -0
- data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +72 -0
- data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +44 -0
- data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +88 -0
- data/lib/concurrent-ruby/concurrent/synchronization/object.rb +183 -0
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +71 -0
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +49 -0
- data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
- data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +36 -0
- data/lib/concurrent-ruby/concurrent/synchronization.rb +30 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +50 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb +74 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +88 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb +246 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb +75 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util.rb +16 -0
- data/lib/concurrent-ruby/concurrent/timer_task.rb +311 -0
- data/lib/concurrent-ruby/concurrent/tuple.rb +86 -0
- data/lib/concurrent-ruby/concurrent/tvar.rb +221 -0
- data/lib/concurrent-ruby/concurrent/utility/engine.rb +56 -0
- data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
- data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
- data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +53 -0
- data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +130 -0
- data/lib/concurrent-ruby/concurrent/version.rb +3 -0
- data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
- data/lib/concurrent-ruby/concurrent.rb +134 -0
- metadata +192 -0
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'concurrent/errors'
|
2
|
+
require 'concurrent/concern/deprecation'
|
3
|
+
require 'concurrent/executor/executor_service'
|
4
|
+
require 'concurrent/synchronization'
|
5
|
+
|
6
|
+
module Concurrent
|
7
|
+
|
8
|
+
# @!macro abstract_executor_service_public_api
|
9
|
+
# @!visibility private
|
10
|
+
class AbstractExecutorService < Synchronization::LockableObject
|
11
|
+
include ExecutorService
|
12
|
+
include Concern::Deprecation
|
13
|
+
|
14
|
+
# The set of possible fallback policies that may be set at thread pool creation.
|
15
|
+
FALLBACK_POLICIES = [:abort, :discard, :caller_runs].freeze
|
16
|
+
|
17
|
+
# @!macro executor_service_attr_reader_fallback_policy
|
18
|
+
attr_reader :fallback_policy
|
19
|
+
|
20
|
+
attr_reader :name
|
21
|
+
|
22
|
+
# Create a new thread pool.
|
23
|
+
def initialize(opts = {}, &block)
|
24
|
+
super(&nil)
|
25
|
+
synchronize do
|
26
|
+
@auto_terminate = opts.fetch(:auto_terminate, true)
|
27
|
+
@name = opts.fetch(:name) if opts.key?(:name)
|
28
|
+
ns_initialize(opts, &block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
name ? "#{super[0..-2]} name: #{name}>" : super
|
34
|
+
end
|
35
|
+
|
36
|
+
# @!macro executor_service_method_shutdown
|
37
|
+
def shutdown
|
38
|
+
raise NotImplementedError
|
39
|
+
end
|
40
|
+
|
41
|
+
# @!macro executor_service_method_kill
|
42
|
+
def kill
|
43
|
+
raise NotImplementedError
|
44
|
+
end
|
45
|
+
|
46
|
+
# @!macro executor_service_method_wait_for_termination
|
47
|
+
def wait_for_termination(timeout = nil)
|
48
|
+
raise NotImplementedError
|
49
|
+
end
|
50
|
+
|
51
|
+
# @!macro executor_service_method_running_question
|
52
|
+
def running?
|
53
|
+
synchronize { ns_running? }
|
54
|
+
end
|
55
|
+
|
56
|
+
# @!macro executor_service_method_shuttingdown_question
|
57
|
+
def shuttingdown?
|
58
|
+
synchronize { ns_shuttingdown? }
|
59
|
+
end
|
60
|
+
|
61
|
+
# @!macro executor_service_method_shutdown_question
|
62
|
+
def shutdown?
|
63
|
+
synchronize { ns_shutdown? }
|
64
|
+
end
|
65
|
+
|
66
|
+
# @!macro executor_service_method_auto_terminate_question
|
67
|
+
def auto_terminate?
|
68
|
+
synchronize { @auto_terminate }
|
69
|
+
end
|
70
|
+
|
71
|
+
# @!macro executor_service_method_auto_terminate_setter
|
72
|
+
def auto_terminate=(value)
|
73
|
+
deprecated "Method #auto_terminate= has no effect. Set :auto_terminate option when executor is initialized."
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# Returns an action which executes the `fallback_policy` once the queue
|
79
|
+
# size reaches `max_queue`. The reason for the indirection of an action
|
80
|
+
# is so that the work can be deferred outside of synchronization.
|
81
|
+
#
|
82
|
+
# @param [Array] args the arguments to the task which is being handled.
|
83
|
+
#
|
84
|
+
# @!visibility private
|
85
|
+
def fallback_action(*args)
|
86
|
+
case fallback_policy
|
87
|
+
when :abort
|
88
|
+
lambda { raise RejectedExecutionError }
|
89
|
+
when :discard
|
90
|
+
lambda { false }
|
91
|
+
when :caller_runs
|
92
|
+
lambda {
|
93
|
+
begin
|
94
|
+
yield(*args)
|
95
|
+
rescue => ex
|
96
|
+
# let it fail
|
97
|
+
log DEBUG, ex
|
98
|
+
end
|
99
|
+
true
|
100
|
+
}
|
101
|
+
else
|
102
|
+
lambda { fail "Unknown fallback policy #{fallback_policy}" }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def ns_execute(*args, &task)
|
107
|
+
raise NotImplementedError
|
108
|
+
end
|
109
|
+
|
110
|
+
# @!macro executor_service_method_ns_shutdown_execution
|
111
|
+
#
|
112
|
+
# Callback method called when an orderly shutdown has completed.
|
113
|
+
# The default behavior is to signal all waiting threads.
|
114
|
+
def ns_shutdown_execution
|
115
|
+
# do nothing
|
116
|
+
end
|
117
|
+
|
118
|
+
# @!macro executor_service_method_ns_kill_execution
|
119
|
+
#
|
120
|
+
# Callback method called when the executor has been killed.
|
121
|
+
# The default behavior is to do nothing.
|
122
|
+
def ns_kill_execution
|
123
|
+
# do nothing
|
124
|
+
end
|
125
|
+
|
126
|
+
def ns_auto_terminate?
|
127
|
+
@auto_terminate
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'concurrent/utility/engine'
|
2
|
+
require 'concurrent/executor/thread_pool_executor'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
# A thread pool that dynamically grows and shrinks to fit the current workload.
|
7
|
+
# New threads are created as needed, existing threads are reused, and threads
|
8
|
+
# that remain idle for too long are killed and removed from the pool. These
|
9
|
+
# pools are particularly suited to applications that perform a high volume of
|
10
|
+
# short-lived tasks.
|
11
|
+
#
|
12
|
+
# On creation a `CachedThreadPool` has zero running threads. New threads are
|
13
|
+
# created on the pool as new operations are `#post`. The size of the pool
|
14
|
+
# will grow until `#max_length` threads are in the pool or until the number
|
15
|
+
# of threads exceeds the number of running and pending operations. When a new
|
16
|
+
# operation is post to the pool the first available idle thread will be tasked
|
17
|
+
# with the new operation.
|
18
|
+
#
|
19
|
+
# Should a thread crash for any reason the thread will immediately be removed
|
20
|
+
# from the pool. Similarly, threads which remain idle for an extended period
|
21
|
+
# of time will be killed and reclaimed. Thus these thread pools are very
|
22
|
+
# efficient at reclaiming unused resources.
|
23
|
+
#
|
24
|
+
# The API and behavior of this class are based on Java's `CachedThreadPool`
|
25
|
+
#
|
26
|
+
# @!macro thread_pool_options
|
27
|
+
class CachedThreadPool < ThreadPoolExecutor
|
28
|
+
|
29
|
+
# @!macro cached_thread_pool_method_initialize
|
30
|
+
#
|
31
|
+
# Create a new thread pool.
|
32
|
+
#
|
33
|
+
# @param [Hash] opts the options defining pool behavior.
|
34
|
+
# @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy
|
35
|
+
#
|
36
|
+
# @raise [ArgumentError] if `fallback_policy` is not a known policy
|
37
|
+
#
|
38
|
+
# @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool--
|
39
|
+
def initialize(opts = {})
|
40
|
+
defaults = { idletime: DEFAULT_THREAD_IDLETIMEOUT }
|
41
|
+
overrides = { min_threads: 0,
|
42
|
+
max_threads: DEFAULT_MAX_POOL_SIZE,
|
43
|
+
max_queue: DEFAULT_MAX_QUEUE_SIZE }
|
44
|
+
super(defaults.merge(opts).merge(overrides))
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# @!macro cached_thread_pool_method_initialize
|
50
|
+
# @!visibility private
|
51
|
+
def ns_initialize(opts)
|
52
|
+
super(opts)
|
53
|
+
if Concurrent.on_jruby?
|
54
|
+
@max_queue = 0
|
55
|
+
@executor = java.util.concurrent.Executors.newCachedThreadPool(
|
56
|
+
DaemonThreadFactory.new(ns_auto_terminate?))
|
57
|
+
@executor.setRejectedExecutionHandler(FALLBACK_POLICY_CLASSES[@fallback_policy].new)
|
58
|
+
@executor.setKeepAliveTime(opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT), java.util.concurrent.TimeUnit::SECONDS)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
require 'concurrent/concern/logging'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
###################################################################
|
6
|
+
|
7
|
+
# @!macro executor_service_method_post
|
8
|
+
#
|
9
|
+
# Submit a task to the executor for asynchronous processing.
|
10
|
+
#
|
11
|
+
# @param [Array] args zero or more arguments to be passed to the task
|
12
|
+
#
|
13
|
+
# @yield the asynchronous task to perform
|
14
|
+
#
|
15
|
+
# @return [Boolean] `true` if the task is queued, `false` if the executor
|
16
|
+
# is not running
|
17
|
+
#
|
18
|
+
# @raise [ArgumentError] if no task is given
|
19
|
+
|
20
|
+
# @!macro executor_service_method_left_shift
|
21
|
+
#
|
22
|
+
# Submit a task to the executor for asynchronous processing.
|
23
|
+
#
|
24
|
+
# @param [Proc] task the asynchronous task to perform
|
25
|
+
#
|
26
|
+
# @return [self] returns itself
|
27
|
+
|
28
|
+
# @!macro executor_service_method_can_overflow_question
|
29
|
+
#
|
30
|
+
# Does the task queue have a maximum size?
|
31
|
+
#
|
32
|
+
# @return [Boolean] True if the task queue has a maximum size else false.
|
33
|
+
|
34
|
+
# @!macro executor_service_method_serialized_question
|
35
|
+
#
|
36
|
+
# Does this executor guarantee serialization of its operations?
|
37
|
+
#
|
38
|
+
# @return [Boolean] True if the executor guarantees that all operations
|
39
|
+
# will be post in the order they are received and no two operations may
|
40
|
+
# occur simultaneously. Else false.
|
41
|
+
|
42
|
+
###################################################################
|
43
|
+
|
44
|
+
# @!macro executor_service_public_api
|
45
|
+
#
|
46
|
+
# @!method post(*args, &task)
|
47
|
+
# @!macro executor_service_method_post
|
48
|
+
#
|
49
|
+
# @!method <<(task)
|
50
|
+
# @!macro executor_service_method_left_shift
|
51
|
+
#
|
52
|
+
# @!method can_overflow?
|
53
|
+
# @!macro executor_service_method_can_overflow_question
|
54
|
+
#
|
55
|
+
# @!method serialized?
|
56
|
+
# @!macro executor_service_method_serialized_question
|
57
|
+
|
58
|
+
###################################################################
|
59
|
+
|
60
|
+
# @!macro executor_service_attr_reader_fallback_policy
|
61
|
+
# @return [Symbol] The fallback policy in effect. Either `:abort`, `:discard`, or `:caller_runs`.
|
62
|
+
|
63
|
+
# @!macro executor_service_method_shutdown
|
64
|
+
#
|
65
|
+
# Begin an orderly shutdown. Tasks already in the queue will be executed,
|
66
|
+
# but no new tasks will be accepted. Has no additional effect if the
|
67
|
+
# thread pool is not running.
|
68
|
+
|
69
|
+
# @!macro executor_service_method_kill
|
70
|
+
#
|
71
|
+
# Begin an immediate shutdown. In-progress tasks will be allowed to
|
72
|
+
# complete but enqueued tasks will be dismissed and no new tasks
|
73
|
+
# will be accepted. Has no additional effect if the thread pool is
|
74
|
+
# not running.
|
75
|
+
|
76
|
+
# @!macro executor_service_method_wait_for_termination
|
77
|
+
#
|
78
|
+
# Block until executor shutdown is complete or until `timeout` seconds have
|
79
|
+
# passed.
|
80
|
+
#
|
81
|
+
# @note Does not initiate shutdown or termination. Either `shutdown` or `kill`
|
82
|
+
# must be called before this method (or on another thread).
|
83
|
+
#
|
84
|
+
# @param [Integer] timeout the maximum number of seconds to wait for shutdown to complete
|
85
|
+
#
|
86
|
+
# @return [Boolean] `true` if shutdown complete or false on `timeout`
|
87
|
+
|
88
|
+
# @!macro executor_service_method_running_question
|
89
|
+
#
|
90
|
+
# Is the executor running?
|
91
|
+
#
|
92
|
+
# @return [Boolean] `true` when running, `false` when shutting down or shutdown
|
93
|
+
|
94
|
+
# @!macro executor_service_method_shuttingdown_question
|
95
|
+
#
|
96
|
+
# Is the executor shuttingdown?
|
97
|
+
#
|
98
|
+
# @return [Boolean] `true` when not running and not shutdown, else `false`
|
99
|
+
|
100
|
+
# @!macro executor_service_method_shutdown_question
|
101
|
+
#
|
102
|
+
# Is the executor shutdown?
|
103
|
+
#
|
104
|
+
# @return [Boolean] `true` when shutdown, `false` when shutting down or running
|
105
|
+
|
106
|
+
# @!macro executor_service_method_auto_terminate_question
|
107
|
+
#
|
108
|
+
# Is the executor auto-terminate when the application exits?
|
109
|
+
#
|
110
|
+
# @return [Boolean] `true` when auto-termination is enabled else `false`.
|
111
|
+
|
112
|
+
# @!macro executor_service_method_auto_terminate_setter
|
113
|
+
#
|
114
|
+
#
|
115
|
+
# Set the auto-terminate behavior for this executor.
|
116
|
+
# @deprecated Has no effect
|
117
|
+
# @param [Boolean] value The new auto-terminate value to set for this executor.
|
118
|
+
# @return [Boolean] `true` when auto-termination is enabled else `false`.
|
119
|
+
|
120
|
+
###################################################################
|
121
|
+
|
122
|
+
# @!macro abstract_executor_service_public_api
|
123
|
+
#
|
124
|
+
# @!macro executor_service_public_api
|
125
|
+
#
|
126
|
+
# @!attribute [r] fallback_policy
|
127
|
+
# @!macro executor_service_attr_reader_fallback_policy
|
128
|
+
#
|
129
|
+
# @!method shutdown
|
130
|
+
# @!macro executor_service_method_shutdown
|
131
|
+
#
|
132
|
+
# @!method kill
|
133
|
+
# @!macro executor_service_method_kill
|
134
|
+
#
|
135
|
+
# @!method wait_for_termination(timeout = nil)
|
136
|
+
# @!macro executor_service_method_wait_for_termination
|
137
|
+
#
|
138
|
+
# @!method running?
|
139
|
+
# @!macro executor_service_method_running_question
|
140
|
+
#
|
141
|
+
# @!method shuttingdown?
|
142
|
+
# @!macro executor_service_method_shuttingdown_question
|
143
|
+
#
|
144
|
+
# @!method shutdown?
|
145
|
+
# @!macro executor_service_method_shutdown_question
|
146
|
+
#
|
147
|
+
# @!method auto_terminate?
|
148
|
+
# @!macro executor_service_method_auto_terminate_question
|
149
|
+
#
|
150
|
+
# @!method auto_terminate=(value)
|
151
|
+
# @!macro executor_service_method_auto_terminate_setter
|
152
|
+
|
153
|
+
###################################################################
|
154
|
+
|
155
|
+
# @!macro executor_service_public_api
|
156
|
+
# @!visibility private
|
157
|
+
module ExecutorService
|
158
|
+
include Concern::Logging
|
159
|
+
|
160
|
+
# @!macro executor_service_method_post
|
161
|
+
def post(*args, &task)
|
162
|
+
raise NotImplementedError
|
163
|
+
end
|
164
|
+
|
165
|
+
# @!macro executor_service_method_left_shift
|
166
|
+
def <<(task)
|
167
|
+
post(&task)
|
168
|
+
self
|
169
|
+
end
|
170
|
+
|
171
|
+
# @!macro executor_service_method_can_overflow_question
|
172
|
+
#
|
173
|
+
# @note Always returns `false`
|
174
|
+
def can_overflow?
|
175
|
+
false
|
176
|
+
end
|
177
|
+
|
178
|
+
# @!macro executor_service_method_serialized_question
|
179
|
+
#
|
180
|
+
# @note Always returns `false`
|
181
|
+
def serialized?
|
182
|
+
false
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
require 'concurrent/utility/engine'
|
2
|
+
require 'concurrent/executor/thread_pool_executor'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
# @!macro thread_pool_executor_constant_default_max_pool_size
|
7
|
+
# Default maximum number of threads that will be created in the pool.
|
8
|
+
|
9
|
+
# @!macro thread_pool_executor_constant_default_min_pool_size
|
10
|
+
# Default minimum number of threads that will be retained in the pool.
|
11
|
+
|
12
|
+
# @!macro thread_pool_executor_constant_default_max_queue_size
|
13
|
+
# Default maximum number of tasks that may be added to the task queue.
|
14
|
+
|
15
|
+
# @!macro thread_pool_executor_constant_default_thread_timeout
|
16
|
+
# Default maximum number of seconds a thread in the pool may remain idle
|
17
|
+
# before being reclaimed.
|
18
|
+
|
19
|
+
# @!macro thread_pool_executor_constant_default_synchronous
|
20
|
+
# Default value of the :synchronous option.
|
21
|
+
|
22
|
+
# @!macro thread_pool_executor_attr_reader_max_length
|
23
|
+
# The maximum number of threads that may be created in the pool.
|
24
|
+
# @return [Integer] The maximum number of threads that may be created in the pool.
|
25
|
+
|
26
|
+
# @!macro thread_pool_executor_attr_reader_min_length
|
27
|
+
# The minimum number of threads that may be retained in the pool.
|
28
|
+
# @return [Integer] The minimum number of threads that may be retained in the pool.
|
29
|
+
|
30
|
+
# @!macro thread_pool_executor_attr_reader_largest_length
|
31
|
+
# The largest number of threads that have been created in the pool since construction.
|
32
|
+
# @return [Integer] The largest number of threads that have been created in the pool since construction.
|
33
|
+
|
34
|
+
# @!macro thread_pool_executor_attr_reader_scheduled_task_count
|
35
|
+
# The number of tasks that have been scheduled for execution on the pool since construction.
|
36
|
+
# @return [Integer] The number of tasks that have been scheduled for execution on the pool since construction.
|
37
|
+
|
38
|
+
# @!macro thread_pool_executor_attr_reader_completed_task_count
|
39
|
+
# The number of tasks that have been completed by the pool since construction.
|
40
|
+
# @return [Integer] The number of tasks that have been completed by the pool since construction.
|
41
|
+
|
42
|
+
# @!macro thread_pool_executor_attr_reader_idletime
|
43
|
+
# The number of seconds that a thread may be idle before being reclaimed.
|
44
|
+
# @return [Integer] The number of seconds that a thread may be idle before being reclaimed.
|
45
|
+
|
46
|
+
# @!macro thread_pool_executor_attr_reader_synchronous
|
47
|
+
# Whether or not a value of 0 for :max_queue option means the queue must perform direct hand-off or rather unbounded queue.
|
48
|
+
# @return [true, false]
|
49
|
+
|
50
|
+
# @!macro thread_pool_executor_attr_reader_max_queue
|
51
|
+
# The maximum number of tasks that may be waiting in the work queue at any one time.
|
52
|
+
# When the queue size reaches `max_queue` subsequent tasks will be rejected in
|
53
|
+
# accordance with the configured `fallback_policy`.
|
54
|
+
#
|
55
|
+
# @return [Integer] The maximum number of tasks that may be waiting in the work queue at any one time.
|
56
|
+
# When the queue size reaches `max_queue` subsequent tasks will be rejected in
|
57
|
+
# accordance with the configured `fallback_policy`.
|
58
|
+
|
59
|
+
# @!macro thread_pool_executor_attr_reader_length
|
60
|
+
# The number of threads currently in the pool.
|
61
|
+
# @return [Integer] The number of threads currently in the pool.
|
62
|
+
|
63
|
+
# @!macro thread_pool_executor_attr_reader_queue_length
|
64
|
+
# The number of tasks in the queue awaiting execution.
|
65
|
+
# @return [Integer] The number of tasks in the queue awaiting execution.
|
66
|
+
|
67
|
+
# @!macro thread_pool_executor_attr_reader_remaining_capacity
|
68
|
+
# Number of tasks that may be enqueued before reaching `max_queue` and rejecting
|
69
|
+
# new tasks. A value of -1 indicates that the queue may grow without bound.
|
70
|
+
#
|
71
|
+
# @return [Integer] Number of tasks that may be enqueued before reaching `max_queue` and rejecting
|
72
|
+
# new tasks. A value of -1 indicates that the queue may grow without bound.
|
73
|
+
|
74
|
+
# @!macro thread_pool_executor_method_prune_pool
|
75
|
+
# Prune the thread pool of unneeded threads
|
76
|
+
#
|
77
|
+
# What is being pruned is controlled by the min_threads and idletime
|
78
|
+
# parameters passed at pool creation time
|
79
|
+
#
|
80
|
+
# This is a no-op on some pool implementation (e.g. the Java one). The Ruby
|
81
|
+
# pool will auto-prune each time a new job is posted. You will need to call
|
82
|
+
# this method explicitely in case your application post jobs in bursts (a
|
83
|
+
# lot of jobs and then nothing for long periods)
|
84
|
+
|
85
|
+
# @!macro thread_pool_executor_public_api
|
86
|
+
#
|
87
|
+
# @!macro abstract_executor_service_public_api
|
88
|
+
#
|
89
|
+
# @!attribute [r] max_length
|
90
|
+
# @!macro thread_pool_executor_attr_reader_max_length
|
91
|
+
#
|
92
|
+
# @!attribute [r] min_length
|
93
|
+
# @!macro thread_pool_executor_attr_reader_min_length
|
94
|
+
#
|
95
|
+
# @!attribute [r] largest_length
|
96
|
+
# @!macro thread_pool_executor_attr_reader_largest_length
|
97
|
+
#
|
98
|
+
# @!attribute [r] scheduled_task_count
|
99
|
+
# @!macro thread_pool_executor_attr_reader_scheduled_task_count
|
100
|
+
#
|
101
|
+
# @!attribute [r] completed_task_count
|
102
|
+
# @!macro thread_pool_executor_attr_reader_completed_task_count
|
103
|
+
#
|
104
|
+
# @!attribute [r] idletime
|
105
|
+
# @!macro thread_pool_executor_attr_reader_idletime
|
106
|
+
#
|
107
|
+
# @!attribute [r] max_queue
|
108
|
+
# @!macro thread_pool_executor_attr_reader_max_queue
|
109
|
+
#
|
110
|
+
# @!attribute [r] length
|
111
|
+
# @!macro thread_pool_executor_attr_reader_length
|
112
|
+
#
|
113
|
+
# @!attribute [r] queue_length
|
114
|
+
# @!macro thread_pool_executor_attr_reader_queue_length
|
115
|
+
#
|
116
|
+
# @!attribute [r] remaining_capacity
|
117
|
+
# @!macro thread_pool_executor_attr_reader_remaining_capacity
|
118
|
+
#
|
119
|
+
# @!method can_overflow?
|
120
|
+
# @!macro executor_service_method_can_overflow_question
|
121
|
+
#
|
122
|
+
# @!method prune_pool
|
123
|
+
# @!macro thread_pool_executor_method_prune_pool
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
|
128
|
+
# @!macro thread_pool_options
|
129
|
+
#
|
130
|
+
# **Thread Pool Options**
|
131
|
+
#
|
132
|
+
# Thread pools support several configuration options:
|
133
|
+
#
|
134
|
+
# * `idletime`: The number of seconds that a thread may be idle before being reclaimed.
|
135
|
+
# * `name`: The name of the executor (optional). Printed in the executor's `#to_s` output and
|
136
|
+
# a `<name>-worker-<id>` name is given to its threads if supported by used Ruby
|
137
|
+
# implementation. `<id>` is uniq for each thread.
|
138
|
+
# * `max_queue`: The maximum number of tasks that may be waiting in the work queue at
|
139
|
+
# any one time. When the queue size reaches `max_queue` and no new threads can be created,
|
140
|
+
# subsequent tasks will be rejected in accordance with the configured `fallback_policy`.
|
141
|
+
# * `auto_terminate`: When true (default), the threads started will be marked as daemon.
|
142
|
+
# * `fallback_policy`: The policy defining how rejected tasks are handled.
|
143
|
+
#
|
144
|
+
# Three fallback policies are supported:
|
145
|
+
#
|
146
|
+
# * `:abort`: Raise a `RejectedExecutionError` exception and discard the task.
|
147
|
+
# * `:discard`: Discard the task and return false.
|
148
|
+
# * `:caller_runs`: Execute the task on the calling thread.
|
149
|
+
#
|
150
|
+
# **Shutting Down Thread Pools**
|
151
|
+
#
|
152
|
+
# Killing a thread pool while tasks are still being processed, either by calling
|
153
|
+
# the `#kill` method or at application exit, will have unpredictable results. There
|
154
|
+
# is no way for the thread pool to know what resources are being used by the
|
155
|
+
# in-progress tasks. When those tasks are killed the impact on those resources
|
156
|
+
# cannot be predicted. The *best* practice is to explicitly shutdown all thread
|
157
|
+
# pools using the provided methods:
|
158
|
+
#
|
159
|
+
# * Call `#shutdown` to initiate an orderly termination of all in-progress tasks
|
160
|
+
# * Call `#wait_for_termination` with an appropriate timeout interval an allow
|
161
|
+
# the orderly shutdown to complete
|
162
|
+
# * Call `#kill` *only when* the thread pool fails to shutdown in the allotted time
|
163
|
+
#
|
164
|
+
# On some runtime platforms (most notably the JVM) the application will not
|
165
|
+
# exit until all thread pools have been shutdown. To prevent applications from
|
166
|
+
# "hanging" on exit, all threads can be marked as daemon according to the
|
167
|
+
# `:auto_terminate` option.
|
168
|
+
#
|
169
|
+
# ```ruby
|
170
|
+
# pool1 = Concurrent::FixedThreadPool.new(5) # threads will be marked as daemon
|
171
|
+
# pool2 = Concurrent::FixedThreadPool.new(5, auto_terminate: false) # mark threads as non-daemon
|
172
|
+
# ```
|
173
|
+
#
|
174
|
+
# @note Failure to properly shutdown a thread pool can lead to unpredictable results.
|
175
|
+
# Please read *Shutting Down Thread Pools* for more information.
|
176
|
+
#
|
177
|
+
# @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html Java Tutorials: Thread Pools
|
178
|
+
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html Java Executors class
|
179
|
+
# @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html Java ExecutorService interface
|
180
|
+
# @see https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#setDaemon-boolean-
|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
|
186
|
+
# @!macro fixed_thread_pool
|
187
|
+
#
|
188
|
+
# A thread pool that reuses a fixed number of threads operating off an unbounded queue.
|
189
|
+
# At any point, at most `num_threads` will be active processing tasks. When all threads are busy new
|
190
|
+
# tasks `#post` to the thread pool are enqueued until a thread becomes available.
|
191
|
+
# Should a thread crash for any reason the thread will immediately be removed
|
192
|
+
# from the pool and replaced.
|
193
|
+
#
|
194
|
+
# The API and behavior of this class are based on Java's `FixedThreadPool`
|
195
|
+
#
|
196
|
+
# @!macro thread_pool_options
|
197
|
+
class FixedThreadPool < ThreadPoolExecutor
|
198
|
+
|
199
|
+
# @!macro fixed_thread_pool_method_initialize
|
200
|
+
#
|
201
|
+
# Create a new thread pool.
|
202
|
+
#
|
203
|
+
# @param [Integer] num_threads the number of threads to allocate
|
204
|
+
# @param [Hash] opts the options defining pool behavior.
|
205
|
+
# @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy
|
206
|
+
#
|
207
|
+
# @raise [ArgumentError] if `num_threads` is less than or equal to zero
|
208
|
+
# @raise [ArgumentError] if `fallback_policy` is not a known policy
|
209
|
+
#
|
210
|
+
# @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool-int-
|
211
|
+
def initialize(num_threads, opts = {})
|
212
|
+
raise ArgumentError.new('number of threads must be greater than zero') if num_threads.to_i < 1
|
213
|
+
defaults = { max_queue: DEFAULT_MAX_QUEUE_SIZE,
|
214
|
+
idletime: DEFAULT_THREAD_IDLETIMEOUT }
|
215
|
+
overrides = { min_threads: num_threads,
|
216
|
+
max_threads: num_threads }
|
217
|
+
super(defaults.merge(opts).merge(overrides))
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'concurrent/atomic/event'
|
2
|
+
require 'concurrent/executor/abstract_executor_service'
|
3
|
+
require 'concurrent/executor/serial_executor_service'
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
|
7
|
+
# An executor service which runs all operations on the current thread,
|
8
|
+
# blocking as necessary. Operations are performed in the order they are
|
9
|
+
# received and no two operations can be performed simultaneously.
|
10
|
+
#
|
11
|
+
# This executor service exists mainly for testing an debugging. When used
|
12
|
+
# it immediately runs every `#post` operation on the current thread, blocking
|
13
|
+
# that thread until the operation is complete. This can be very beneficial
|
14
|
+
# during testing because it makes all operations deterministic.
|
15
|
+
#
|
16
|
+
# @note Intended for use primarily in testing and debugging.
|
17
|
+
class ImmediateExecutor < AbstractExecutorService
|
18
|
+
include SerialExecutorService
|
19
|
+
|
20
|
+
# Creates a new executor
|
21
|
+
def initialize
|
22
|
+
@stopped = Concurrent::Event.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# @!macro executor_service_method_post
|
26
|
+
def post(*args, &task)
|
27
|
+
raise ArgumentError.new('no block given') unless block_given?
|
28
|
+
return false unless running?
|
29
|
+
task.call(*args)
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
# @!macro executor_service_method_left_shift
|
34
|
+
def <<(task)
|
35
|
+
post(&task)
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
# @!macro executor_service_method_running_question
|
40
|
+
def running?
|
41
|
+
! shutdown?
|
42
|
+
end
|
43
|
+
|
44
|
+
# @!macro executor_service_method_shuttingdown_question
|
45
|
+
def shuttingdown?
|
46
|
+
false
|
47
|
+
end
|
48
|
+
|
49
|
+
# @!macro executor_service_method_shutdown_question
|
50
|
+
def shutdown?
|
51
|
+
@stopped.set?
|
52
|
+
end
|
53
|
+
|
54
|
+
# @!macro executor_service_method_shutdown
|
55
|
+
def shutdown
|
56
|
+
@stopped.set
|
57
|
+
true
|
58
|
+
end
|
59
|
+
alias_method :kill, :shutdown
|
60
|
+
|
61
|
+
# @!macro executor_service_method_wait_for_termination
|
62
|
+
def wait_for_termination(timeout = nil)
|
63
|
+
@stopped.wait(timeout)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|