concurrent-ruby 0.8.0.pre2-java → 0.9.0-java
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 +114 -3
- data/README.md +111 -55
- data/lib/concurrent.rb +90 -14
- data/lib/concurrent/async.rb +143 -51
- data/lib/concurrent/atom.rb +131 -0
- data/lib/concurrent/atomic/atomic_boolean.rb +57 -107
- data/lib/concurrent/atomic/atomic_fixnum.rb +73 -101
- data/lib/concurrent/atomic/atomic_reference.rb +49 -0
- data/lib/concurrent/atomic/condition.rb +23 -12
- data/lib/concurrent/atomic/count_down_latch.rb +23 -21
- data/lib/concurrent/atomic/cyclic_barrier.rb +47 -47
- data/lib/concurrent/atomic/event.rb +33 -42
- data/lib/concurrent/atomic/read_write_lock.rb +252 -0
- data/lib/concurrent/atomic/semaphore.rb +64 -89
- data/lib/concurrent/atomic/thread_local_var.rb +130 -58
- data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +236 -0
- data/lib/concurrent/atomic_reference/direct_update.rb +34 -3
- data/lib/concurrent/atomic_reference/jruby.rb +6 -3
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +17 -39
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +3 -0
- data/lib/concurrent/atomic_reference/rbx.rb +4 -1
- data/lib/concurrent/atomic_reference/ruby.rb +6 -3
- data/lib/concurrent/atomics.rb +74 -4
- data/lib/concurrent/collection/copy_on_notify_observer_set.rb +115 -0
- data/lib/concurrent/collection/copy_on_write_observer_set.rb +119 -0
- data/lib/concurrent/collection/priority_queue.rb +300 -245
- data/lib/concurrent/concern/deprecation.rb +34 -0
- data/lib/concurrent/concern/dereferenceable.rb +88 -0
- data/lib/concurrent/concern/logging.rb +27 -0
- data/lib/concurrent/concern/obligation.rb +228 -0
- data/lib/concurrent/concern/observable.rb +85 -0
- data/lib/concurrent/configuration.rb +234 -109
- data/lib/concurrent/dataflow.rb +2 -3
- data/lib/concurrent/delay.rb +141 -50
- data/lib/concurrent/edge.rb +30 -0
- data/lib/concurrent/errors.rb +19 -7
- data/lib/concurrent/exchanger.rb +25 -1
- data/lib/concurrent/executor/cached_thread_pool.rb +51 -33
- data/lib/concurrent/executor/executor.rb +46 -299
- data/lib/concurrent/executor/executor_service.rb +521 -0
- data/lib/concurrent/executor/fixed_thread_pool.rb +196 -23
- data/lib/concurrent/executor/immediate_executor.rb +9 -9
- data/lib/concurrent/executor/indirect_immediate_executor.rb +4 -3
- data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
- data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
- data/lib/concurrent/executor/safe_task_executor.rb +5 -4
- data/lib/concurrent/executor/serialized_execution.rb +22 -18
- data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
- data/lib/concurrent/executor/single_thread_executor.rb +32 -21
- data/lib/concurrent/executor/thread_pool_executor.rb +73 -60
- data/lib/concurrent/executor/timer_set.rb +96 -84
- data/lib/concurrent/executors.rb +1 -1
- data/lib/concurrent/future.rb +71 -38
- data/lib/concurrent/immutable_struct.rb +89 -0
- data/lib/concurrent/ivar.rb +152 -60
- data/lib/concurrent/lazy_register.rb +40 -20
- data/lib/concurrent/maybe.rb +226 -0
- data/lib/concurrent/mutable_struct.rb +227 -0
- data/lib/concurrent/mvar.rb +44 -43
- data/lib/concurrent/promise.rb +229 -136
- data/lib/concurrent/scheduled_task.rb +341 -43
- data/lib/concurrent/settable_struct.rb +127 -0
- data/lib/concurrent/synchronization.rb +17 -0
- data/lib/concurrent/synchronization/abstract_object.rb +163 -0
- data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
- data/lib/concurrent/synchronization/condition.rb +53 -0
- data/lib/concurrent/synchronization/java_object.rb +34 -0
- data/lib/concurrent/synchronization/lock.rb +32 -0
- data/lib/concurrent/synchronization/monitor_object.rb +26 -0
- data/lib/concurrent/synchronization/mutex_object.rb +43 -0
- data/lib/concurrent/synchronization/object.rb +78 -0
- data/lib/concurrent/synchronization/rbx_object.rb +75 -0
- data/lib/concurrent/timer_task.rb +92 -103
- data/lib/concurrent/tvar.rb +42 -38
- data/lib/concurrent/utilities.rb +3 -1
- data/lib/concurrent/utility/at_exit.rb +97 -0
- data/lib/concurrent/utility/engine.rb +44 -0
- data/lib/concurrent/utility/monotonic_time.rb +59 -0
- data/lib/concurrent/utility/native_extension_loader.rb +56 -0
- data/lib/concurrent/utility/processor_counter.rb +156 -0
- data/lib/concurrent/utility/timeout.rb +18 -14
- data/lib/concurrent/utility/timer.rb +11 -6
- data/lib/concurrent/version.rb +2 -1
- data/lib/concurrent_ruby.rb +1 -0
- data/lib/concurrent_ruby_ext.jar +0 -0
- metadata +46 -66
- data/lib/concurrent/actor.rb +0 -103
- data/lib/concurrent/actor/behaviour.rb +0 -70
- data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
- data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
- data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
- data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
- data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
- data/lib/concurrent/actor/behaviour/linking.rb +0 -45
- data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
- data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
- data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
- data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
- data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
- data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
- data/lib/concurrent/actor/behaviour/termination.rb +0 -54
- data/lib/concurrent/actor/context.rb +0 -154
- data/lib/concurrent/actor/core.rb +0 -217
- data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
- data/lib/concurrent/actor/envelope.rb +0 -41
- data/lib/concurrent/actor/errors.rb +0 -27
- data/lib/concurrent/actor/internal_delegations.rb +0 -49
- data/lib/concurrent/actor/public_delegations.rb +0 -40
- data/lib/concurrent/actor/reference.rb +0 -81
- data/lib/concurrent/actor/root.rb +0 -37
- data/lib/concurrent/actor/type_check.rb +0 -48
- data/lib/concurrent/actor/utils.rb +0 -10
- data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
- data/lib/concurrent/actor/utils/balancer.rb +0 -42
- data/lib/concurrent/actor/utils/broadcast.rb +0 -52
- data/lib/concurrent/actor/utils/pool.rb +0 -59
- data/lib/concurrent/actress.rb +0 -3
- data/lib/concurrent/agent.rb +0 -209
- data/lib/concurrent/atomic.rb +0 -92
- data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
- data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
- data/lib/concurrent/atomic/synchronization.rb +0 -51
- data/lib/concurrent/channel/buffered_channel.rb +0 -85
- data/lib/concurrent/channel/channel.rb +0 -41
- data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
- data/lib/concurrent/channel/waitable_list.rb +0 -40
- data/lib/concurrent/channels.rb +0 -5
- data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
- data/lib/concurrent/collection/ring_buffer.rb +0 -59
- data/lib/concurrent/collections.rb +0 -3
- data/lib/concurrent/dereferenceable.rb +0 -108
- data/lib/concurrent/executor/java_cached_thread_pool.rb +0 -32
- data/lib/concurrent/executor/java_fixed_thread_pool.rb +0 -31
- data/lib/concurrent/executor/ruby_cached_thread_pool.rb +0 -29
- data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +0 -32
- data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
- data/lib/concurrent/logging.rb +0 -20
- data/lib/concurrent/obligation.rb +0 -171
- data/lib/concurrent/observable.rb +0 -73
- data/lib/concurrent/options_parser.rb +0 -48
- data/lib/concurrent/utility/processor_count.rb +0 -152
- data/lib/extension_helper.rb +0 -37
@@ -0,0 +1,30 @@
|
|
1
|
+
module Concurrent
|
2
|
+
|
3
|
+
# A submodule for unstable, highly experimental features that are likely to
|
4
|
+
# change often and which may never become part of the core gem. Also for
|
5
|
+
# new, experimental version of abstractions already in the core gem.
|
6
|
+
#
|
7
|
+
# Most new features should start in this module, clearly indicating the
|
8
|
+
# experimental and unstable nature of the feature. Once a feature becomes
|
9
|
+
# more stable and is a candidate for inclusion in the core gem it should
|
10
|
+
# be moved up to the `Concurrent` module, where it would reside once merged
|
11
|
+
# into the core gem.
|
12
|
+
#
|
13
|
+
# The only exception to this is for features which *replace* features from
|
14
|
+
# the core gem in ways that are breaking and not backward compatible. These
|
15
|
+
# features should remain in this module until merged into the core gem. This
|
16
|
+
# will prevent namespace collisions.
|
17
|
+
#
|
18
|
+
# This file should *never* be used as a global `require` for all files within
|
19
|
+
# the edge gem. Because these features are experimental users should always
|
20
|
+
# explicitly require only what they need.
|
21
|
+
#
|
22
|
+
# @!macro [attach] edge_warning
|
23
|
+
# @api Edge
|
24
|
+
# @note **Edge Feature:** Edge features are under active development and may change frequently. They are expected not to
|
25
|
+
# keep backward compatibility (there may also lack tests and documentation). Semantic versions will
|
26
|
+
# be obeyed though. Features developed in `concurrent-ruby-edge` are expected to move
|
27
|
+
# to `concurrent-ruby` when final.
|
28
|
+
module Edge
|
29
|
+
end
|
30
|
+
end
|
data/lib/concurrent/errors.rb
CHANGED
@@ -1,30 +1,42 @@
|
|
1
1
|
module Concurrent
|
2
2
|
|
3
|
+
Error = Class.new(StandardError)
|
4
|
+
|
3
5
|
# Raised when errors occur during configuration.
|
4
|
-
ConfigurationError = Class.new(
|
6
|
+
ConfigurationError = Class.new(Error)
|
7
|
+
|
8
|
+
# Raised when an asynchronous operation is cancelled before execution.
|
9
|
+
CancelledOperationError = Class.new(Error)
|
5
10
|
|
6
11
|
# Raised when a lifecycle method (such as `stop`) is called in an improper
|
7
12
|
# sequence or when the object is in an inappropriate state.
|
8
|
-
LifecycleError = Class.new(
|
13
|
+
LifecycleError = Class.new(Error)
|
14
|
+
|
15
|
+
# Raised when an attempt is made to violate an immutability guarantee.
|
16
|
+
ImmutabilityError = Class.new(Error)
|
9
17
|
|
10
18
|
# Raised when an object's methods are called when it has not been
|
11
19
|
# properly initialized.
|
12
|
-
InitializationError = Class.new(
|
20
|
+
InitializationError = Class.new(Error)
|
13
21
|
|
14
22
|
# Raised when an object with a start/stop lifecycle has been started an
|
15
23
|
# excessive number of times. Often used in conjunction with a restart
|
16
24
|
# policy or strategy.
|
17
|
-
MaxRestartFrequencyError = Class.new(
|
25
|
+
MaxRestartFrequencyError = Class.new(Error)
|
18
26
|
|
19
27
|
# Raised when an attempt is made to modify an immutable object
|
20
28
|
# (such as an `IVar`) after its final state has been set.
|
21
|
-
MultipleAssignmentError = Class.new(
|
29
|
+
MultipleAssignmentError = Class.new(Error)
|
22
30
|
|
23
31
|
# Raised by an `Executor` when it is unable to process a given task,
|
24
32
|
# possibly because of a reject policy or other internal error.
|
25
|
-
RejectedExecutionError = Class.new(
|
33
|
+
RejectedExecutionError = Class.new(Error)
|
34
|
+
|
35
|
+
# Raised when any finite resource, such as a lock counter, exceeds its
|
36
|
+
# maximum limit/threshold.
|
37
|
+
ResourceLimitError = Class.new(Error)
|
26
38
|
|
27
39
|
# Raised when an operation times out.
|
28
|
-
TimeoutError = Class.new(
|
40
|
+
TimeoutError = Class.new(Error)
|
29
41
|
|
30
42
|
end
|
data/lib/concurrent/exchanger.rb
CHANGED
@@ -1,15 +1,39 @@
|
|
1
1
|
module Concurrent
|
2
|
+
|
3
|
+
# A synchronization point at which threads can pair and swap elements within
|
4
|
+
# pairs. Each thread presents some object on entry to the exchange method,
|
5
|
+
# matches with a partner thread, and receives its partner's object on return.
|
6
|
+
#
|
7
|
+
# Uses `MVar` to manage synchronization of the individual elements.
|
8
|
+
# Since `MVar` is also a `Dereferenceable`, the exchanged values support all
|
9
|
+
# dereferenceable options. The constructor options hash will be passed to
|
10
|
+
# the `MVar` constructors.
|
11
|
+
#
|
12
|
+
# @see Concurrent::MVar
|
13
|
+
# @see Concurrent::Concern::Dereferenceable
|
14
|
+
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Exchanger.html java.util.concurrent.Exchanger
|
15
|
+
#
|
16
|
+
# @!macro edge_warning
|
2
17
|
class Exchanger
|
3
18
|
|
4
19
|
EMPTY = Object.new
|
5
20
|
|
21
|
+
# Create a new `Exchanger` object.
|
22
|
+
#
|
23
|
+
# @param [Hash] opts the options controlling how the managed references
|
24
|
+
# will be processed
|
6
25
|
def initialize(opts = {})
|
7
26
|
@first = MVar.new(EMPTY, opts)
|
8
27
|
@second = MVar.new(MVar::EMPTY, opts)
|
9
28
|
end
|
10
29
|
|
30
|
+
# Waits for another thread to arrive at this exchange point (unless the
|
31
|
+
# current thread is interrupted), and then transfers the given object to
|
32
|
+
# it, receiving its object in return.
|
33
|
+
#
|
11
34
|
# @param [Object] value the value to exchange with an other thread
|
12
|
-
# @param [Numeric] timeout the maximum time in second to wait for one other
|
35
|
+
# @param [Numeric] timeout the maximum time in second to wait for one other
|
36
|
+
# thread. nil (default value) means no timeout
|
13
37
|
# @return [Object] the value exchanged by the other thread; nil if timed out
|
14
38
|
def exchange(value, timeout = nil)
|
15
39
|
first = @first.take(timeout)
|
@@ -1,44 +1,62 @@
|
|
1
|
-
require 'concurrent/
|
1
|
+
require 'concurrent/utility/engine'
|
2
|
+
require 'concurrent/executor/thread_pool_executor'
|
2
3
|
|
3
4
|
module Concurrent
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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 [attach] cached_thread_pool_method_initialize
|
25
30
|
#
|
26
|
-
#
|
31
|
+
# Create a new thread pool.
|
27
32
|
#
|
28
|
-
# @
|
29
|
-
#
|
33
|
+
# @param [Hash] opts the options defining pool behavior.
|
34
|
+
# @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy
|
30
35
|
#
|
31
|
-
# @
|
32
|
-
# @see Concurrent::JavaCachedThreadPool
|
36
|
+
# @raise [ArgumentError] if `fallback_policy` is not a known policy
|
33
37
|
#
|
34
|
-
# @see http://docs.oracle.com/javase/
|
35
|
-
|
36
|
-
|
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))
|
38
45
|
end
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
+
@executor.setRejectedExecutionHandler(FALLBACK_POLICY_CLASSES[@fallback_policy].new)
|
57
|
+
@executor.setKeepAliveTime(opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT), java.util.concurrent.TimeUnit::SECONDS)
|
58
|
+
self.auto_terminate = opts.fetch(:auto_terminate, true)
|
59
|
+
end
|
42
60
|
end
|
43
61
|
end
|
44
62
|
end
|
@@ -1,319 +1,66 @@
|
|
1
|
-
require 'concurrent/
|
2
|
-
require 'concurrent/
|
3
|
-
require 'concurrent/atomic/event'
|
1
|
+
require 'concurrent/executor/executor_service'
|
2
|
+
require 'concurrent/concern/deprecation'
|
4
3
|
|
5
4
|
module Concurrent
|
6
5
|
|
6
|
+
# @!visibility private
|
7
7
|
module Executor
|
8
|
-
|
9
|
-
# queue size reaches the configured `max_queue`, or after the
|
10
|
-
# executor has shut down) are handled. Must be one of the values
|
11
|
-
# specified in `FALLBACK_POLICIES`.
|
12
|
-
attr_reader :fallback_policy
|
8
|
+
extend Concern::Deprecation
|
13
9
|
|
14
|
-
#
|
10
|
+
# Get the requested `Executor` based on the values set in the options hash.
|
15
11
|
#
|
16
|
-
#
|
12
|
+
# @param [Hash] opts the options defining the requested executor
|
13
|
+
# @option opts [Executor] :executor when set use the given `Executor` instance.
|
14
|
+
# Three special values are also supported: `:fast` returns the global fast executor,
|
15
|
+
# `:io` returns the global io executor, and `:immediate` returns a new
|
16
|
+
# `ImmediateExecutor` object.
|
17
17
|
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
# @note Always returns `false`
|
21
|
-
def can_overflow?
|
22
|
-
false
|
23
|
-
end
|
24
|
-
|
25
|
-
# Handler which executes the `fallback_policy` once the queue size
|
26
|
-
# reaches `max_queue`.
|
27
|
-
#
|
28
|
-
# @param [Array] args the arguments to the task which is being handled.
|
18
|
+
# @return [Executor, nil] the requested thread pool, or nil when no option specified
|
29
19
|
#
|
30
20
|
# @!visibility private
|
31
|
-
def
|
32
|
-
case
|
33
|
-
when :
|
34
|
-
|
35
|
-
|
36
|
-
false
|
37
|
-
when :caller_runs
|
38
|
-
begin
|
39
|
-
yield(*args)
|
40
|
-
rescue => ex
|
41
|
-
# let it fail
|
42
|
-
log DEBUG, ex
|
43
|
-
end
|
44
|
-
true
|
45
|
-
else
|
46
|
-
fail "Unknown fallback policy #{@fallback_policy}"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# @!macro [attach] executor_module_method_serialized_question
|
51
|
-
#
|
52
|
-
# Does this executor guarantee serialization of its operations?
|
53
|
-
#
|
54
|
-
# @return [Boolean] True if the executor guarantees that all operations
|
55
|
-
# will be post in the order they are received and no two operations may
|
56
|
-
# occur simultaneously. Else false.
|
57
|
-
#
|
58
|
-
# @note Always returns `false`
|
59
|
-
def serialized?
|
60
|
-
false
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
# Indicates that the including `Executor` or `ExecutorService` guarantees
|
65
|
-
# that all operations will occur in the order they are post and that no
|
66
|
-
# two operations may occur simultaneously. This module provides no
|
67
|
-
# functionality and provides no guarantees. That is the responsibility
|
68
|
-
# of the including class. This module exists solely to allow the including
|
69
|
-
# object to be interrogated for its serialization status.
|
70
|
-
#
|
71
|
-
# @example
|
72
|
-
# class Foo
|
73
|
-
# include Concurrent::SerialExecutor
|
74
|
-
# end
|
75
|
-
#
|
76
|
-
# foo = Foo.new
|
77
|
-
#
|
78
|
-
# foo.is_a? Concurrent::Executor #=> true
|
79
|
-
# foo.is_a? Concurrent::SerialExecutor #=> true
|
80
|
-
# foo.serialized? #=> true
|
81
|
-
module SerialExecutor
|
82
|
-
include Executor
|
83
|
-
|
84
|
-
# @!macro executor_module_method_serialized_question
|
85
|
-
#
|
86
|
-
# @note Always returns `true`
|
87
|
-
def serialized?
|
88
|
-
true
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
module RubyExecutor
|
93
|
-
include Executor
|
94
|
-
include Logging
|
95
|
-
|
96
|
-
# The set of possible fallback policies that may be set at thread pool creation.
|
97
|
-
FALLBACK_POLICIES = [:abort, :discard, :caller_runs]
|
98
|
-
|
99
|
-
# @!macro [attach] executor_method_post
|
100
|
-
#
|
101
|
-
# Submit a task to the executor for asynchronous processing.
|
102
|
-
#
|
103
|
-
# @param [Array] args zero or more arguments to be passed to the task
|
104
|
-
#
|
105
|
-
# @yield the asynchronous task to perform
|
106
|
-
#
|
107
|
-
# @return [Boolean] `true` if the task is queued, `false` if the executor
|
108
|
-
# is not running
|
109
|
-
#
|
110
|
-
# @raise [ArgumentError] if no task is given
|
111
|
-
def post(*args, &task)
|
112
|
-
raise ArgumentError.new('no block given') unless block_given?
|
113
|
-
mutex.synchronize do
|
114
|
-
# If the executor is shut down, reject this task
|
115
|
-
return handle_fallback(*args, &task) unless running?
|
116
|
-
execute(*args, &task)
|
117
|
-
true
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
# @!macro [attach] executor_method_left_shift
|
122
|
-
#
|
123
|
-
# Submit a task to the executor for asynchronous processing.
|
124
|
-
#
|
125
|
-
# @param [Proc] task the asynchronous task to perform
|
126
|
-
#
|
127
|
-
# @return [self] returns itself
|
128
|
-
def <<(task)
|
129
|
-
post(&task)
|
130
|
-
self
|
131
|
-
end
|
132
|
-
|
133
|
-
# @!macro [attach] executor_method_running_question
|
134
|
-
#
|
135
|
-
# Is the executor running?
|
136
|
-
#
|
137
|
-
# @return [Boolean] `true` when running, `false` when shutting down or shutdown
|
138
|
-
def running?
|
139
|
-
! stop_event.set?
|
140
|
-
end
|
141
|
-
|
142
|
-
# @!macro [attach] executor_method_shuttingdown_question
|
143
|
-
#
|
144
|
-
# Is the executor shuttingdown?
|
145
|
-
#
|
146
|
-
# @return [Boolean] `true` when not running and not shutdown, else `false`
|
147
|
-
def shuttingdown?
|
148
|
-
! (running? || shutdown?)
|
149
|
-
end
|
150
|
-
|
151
|
-
# @!macro [attach] executor_method_shutdown_question
|
152
|
-
#
|
153
|
-
# Is the executor shutdown?
|
154
|
-
#
|
155
|
-
# @return [Boolean] `true` when shutdown, `false` when shutting down or running
|
156
|
-
def shutdown?
|
157
|
-
stopped_event.set?
|
158
|
-
end
|
159
|
-
|
160
|
-
# @!macro [attach] executor_method_shutdown
|
161
|
-
#
|
162
|
-
# Begin an orderly shutdown. Tasks already in the queue will be executed,
|
163
|
-
# but no new tasks will be accepted. Has no additional effect if the
|
164
|
-
# thread pool is not running.
|
165
|
-
def shutdown
|
166
|
-
mutex.synchronize do
|
167
|
-
break unless running?
|
168
|
-
stop_event.set
|
169
|
-
shutdown_execution
|
170
|
-
end
|
171
|
-
true
|
172
|
-
end
|
173
|
-
|
174
|
-
# @!macro [attach] executor_method_kill
|
175
|
-
#
|
176
|
-
# Begin an immediate shutdown. In-progress tasks will be allowed to
|
177
|
-
# complete but enqueued tasks will be dismissed and no new tasks
|
178
|
-
# will be accepted. Has no additional effect if the thread pool is
|
179
|
-
# not running.
|
180
|
-
def kill
|
181
|
-
mutex.synchronize do
|
182
|
-
break if shutdown?
|
183
|
-
stop_event.set
|
184
|
-
kill_execution
|
185
|
-
stopped_event.set
|
186
|
-
end
|
187
|
-
true
|
188
|
-
end
|
189
|
-
|
190
|
-
# @!macro [attach] executor_method_wait_for_termination
|
191
|
-
#
|
192
|
-
# Block until executor shutdown is complete or until `timeout` seconds have
|
193
|
-
# passed.
|
194
|
-
#
|
195
|
-
# @note Does not initiate shutdown or termination. Either `shutdown` or `kill`
|
196
|
-
# must be called before this method (or on another thread).
|
197
|
-
#
|
198
|
-
# @param [Integer] timeout the maximum number of seconds to wait for shutdown to complete
|
199
|
-
#
|
200
|
-
# @return [Boolean] `true` if shutdown complete or false on `timeout`
|
201
|
-
def wait_for_termination(timeout = nil)
|
202
|
-
stopped_event.wait(timeout)
|
203
|
-
end
|
204
|
-
|
205
|
-
protected
|
206
|
-
|
207
|
-
attr_reader :mutex, :stop_event, :stopped_event
|
208
|
-
|
209
|
-
# @!macro [attach] executor_method_init_executor
|
210
|
-
#
|
211
|
-
# Initialize the executor by creating and initializing all the
|
212
|
-
# internal synchronization objects.
|
213
|
-
def init_executor
|
214
|
-
@mutex = Mutex.new
|
215
|
-
@stop_event = Event.new
|
216
|
-
@stopped_event = Event.new
|
217
|
-
end
|
218
|
-
|
219
|
-
# @!macro [attach] executor_method_execute
|
220
|
-
def execute(*args, &task)
|
221
|
-
raise NotImplementedError
|
222
|
-
end
|
223
|
-
|
224
|
-
# @!macro [attach] executor_method_shutdown_execution
|
225
|
-
#
|
226
|
-
# Callback method called when an orderly shutdown has completed.
|
227
|
-
# The default behavior is to signal all waiting threads.
|
228
|
-
def shutdown_execution
|
229
|
-
stopped_event.set
|
230
|
-
end
|
231
|
-
|
232
|
-
# @!macro [attach] executor_method_kill_execution
|
233
|
-
#
|
234
|
-
# Callback method called when the executor has been killed.
|
235
|
-
# The default behavior is to do nothing.
|
236
|
-
def kill_execution
|
237
|
-
# do nothing
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
if RUBY_PLATFORM == 'java'
|
242
|
-
|
243
|
-
module JavaExecutor
|
244
|
-
include Executor
|
245
|
-
java_import 'java.lang.Runnable'
|
246
|
-
|
247
|
-
# The set of possible fallback policies that may be set at thread pool creation.
|
248
|
-
FALLBACK_POLICIES = {
|
249
|
-
abort: java.util.concurrent.ThreadPoolExecutor::AbortPolicy,
|
250
|
-
discard: java.util.concurrent.ThreadPoolExecutor::DiscardPolicy,
|
251
|
-
caller_runs: java.util.concurrent.ThreadPoolExecutor::CallerRunsPolicy
|
252
|
-
}.freeze
|
253
|
-
|
254
|
-
# @!macro executor_method_post
|
255
|
-
def post(*args, &task)
|
256
|
-
raise ArgumentError.new('no block given') unless block_given?
|
257
|
-
return handle_fallback(*args, &task) unless running?
|
258
|
-
executor_submit = @executor.java_method(:submit, [Runnable.java_class])
|
259
|
-
executor_submit.call { yield(*args) }
|
260
|
-
true
|
261
|
-
rescue Java::JavaUtilConcurrent::RejectedExecutionException
|
262
|
-
raise RejectedExecutionError
|
263
|
-
end
|
264
|
-
|
265
|
-
# @!macro executor_method_left_shift
|
266
|
-
def <<(task)
|
267
|
-
post(&task)
|
268
|
-
self
|
269
|
-
end
|
270
|
-
|
271
|
-
# @!macro executor_method_running_question
|
272
|
-
def running?
|
273
|
-
! (shuttingdown? || shutdown?)
|
274
|
-
end
|
275
|
-
|
276
|
-
# @!macro executor_method_shuttingdown_question
|
277
|
-
def shuttingdown?
|
278
|
-
if @executor.respond_to? :isTerminating
|
279
|
-
@executor.isTerminating
|
21
|
+
def self.executor_from_options(opts = {}) # :nodoc:
|
22
|
+
case
|
23
|
+
when opts.key?(:executor)
|
24
|
+
if opts[:executor].nil?
|
25
|
+
nil
|
280
26
|
else
|
281
|
-
|
27
|
+
executor(opts[:executor])
|
282
28
|
end
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
@executor.isShutdown || @executor.isTerminated
|
288
|
-
end
|
289
|
-
|
290
|
-
# @!macro executor_method_wait_for_termination
|
291
|
-
def wait_for_termination(timeout = nil)
|
292
|
-
if timeout.nil?
|
293
|
-
ok = @executor.awaitTermination(60, java.util.concurrent.TimeUnit::SECONDS) until ok
|
294
|
-
true
|
295
|
-
else
|
296
|
-
@executor.awaitTermination(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
|
29
|
+
when opts.key?(:operation) || opts.key?(:task)
|
30
|
+
if opts[:operation] == true || opts[:task] == false
|
31
|
+
deprecated 'use `executor: :fast` instead'
|
32
|
+
return Concurrent.global_fast_executor
|
297
33
|
end
|
298
|
-
end
|
299
34
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
end
|
35
|
+
if opts[:operation] == false || opts[:task] == true
|
36
|
+
deprecated 'use `executor: :io` instead'
|
37
|
+
return Concurrent.global_io_executor
|
38
|
+
end
|
305
39
|
|
306
|
-
|
307
|
-
|
308
|
-
@executor.shutdownNow
|
40
|
+
raise ArgumentError.new("executor '#{opts[:executor]}' not recognized")
|
41
|
+
else
|
309
42
|
nil
|
310
43
|
end
|
44
|
+
end
|
311
45
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
46
|
+
def self.executor(executor_identifier)
|
47
|
+
case executor_identifier
|
48
|
+
when :fast
|
49
|
+
Concurrent.global_fast_executor
|
50
|
+
when :io
|
51
|
+
Concurrent.global_io_executor
|
52
|
+
when :immediate
|
53
|
+
Concurrent.global_immediate_executor
|
54
|
+
when :operation
|
55
|
+
deprecated 'use `executor: :fast` instead'
|
56
|
+
Concurrent.global_fast_executor
|
57
|
+
when :task
|
58
|
+
deprecated 'use `executor: :io` instead'
|
59
|
+
Concurrent.global_io_executor
|
60
|
+
when Concurrent::ExecutorService
|
61
|
+
executor_identifier
|
62
|
+
else
|
63
|
+
raise ArgumentError, "executor not recognized by '#{executor_identifier}'"
|
317
64
|
end
|
318
65
|
end
|
319
66
|
end
|