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.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +114 -3
  3. data/README.md +111 -55
  4. data/lib/concurrent.rb +90 -14
  5. data/lib/concurrent/async.rb +143 -51
  6. data/lib/concurrent/atom.rb +131 -0
  7. data/lib/concurrent/atomic/atomic_boolean.rb +57 -107
  8. data/lib/concurrent/atomic/atomic_fixnum.rb +73 -101
  9. data/lib/concurrent/atomic/atomic_reference.rb +49 -0
  10. data/lib/concurrent/atomic/condition.rb +23 -12
  11. data/lib/concurrent/atomic/count_down_latch.rb +23 -21
  12. data/lib/concurrent/atomic/cyclic_barrier.rb +47 -47
  13. data/lib/concurrent/atomic/event.rb +33 -42
  14. data/lib/concurrent/atomic/read_write_lock.rb +252 -0
  15. data/lib/concurrent/atomic/semaphore.rb +64 -89
  16. data/lib/concurrent/atomic/thread_local_var.rb +130 -58
  17. data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +236 -0
  18. data/lib/concurrent/atomic_reference/direct_update.rb +34 -3
  19. data/lib/concurrent/atomic_reference/jruby.rb +6 -3
  20. data/lib/concurrent/atomic_reference/mutex_atomic.rb +17 -39
  21. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +3 -0
  22. data/lib/concurrent/atomic_reference/rbx.rb +4 -1
  23. data/lib/concurrent/atomic_reference/ruby.rb +6 -3
  24. data/lib/concurrent/atomics.rb +74 -4
  25. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +115 -0
  26. data/lib/concurrent/collection/copy_on_write_observer_set.rb +119 -0
  27. data/lib/concurrent/collection/priority_queue.rb +300 -245
  28. data/lib/concurrent/concern/deprecation.rb +34 -0
  29. data/lib/concurrent/concern/dereferenceable.rb +88 -0
  30. data/lib/concurrent/concern/logging.rb +27 -0
  31. data/lib/concurrent/concern/obligation.rb +228 -0
  32. data/lib/concurrent/concern/observable.rb +85 -0
  33. data/lib/concurrent/configuration.rb +234 -109
  34. data/lib/concurrent/dataflow.rb +2 -3
  35. data/lib/concurrent/delay.rb +141 -50
  36. data/lib/concurrent/edge.rb +30 -0
  37. data/lib/concurrent/errors.rb +19 -7
  38. data/lib/concurrent/exchanger.rb +25 -1
  39. data/lib/concurrent/executor/cached_thread_pool.rb +51 -33
  40. data/lib/concurrent/executor/executor.rb +46 -299
  41. data/lib/concurrent/executor/executor_service.rb +521 -0
  42. data/lib/concurrent/executor/fixed_thread_pool.rb +196 -23
  43. data/lib/concurrent/executor/immediate_executor.rb +9 -9
  44. data/lib/concurrent/executor/indirect_immediate_executor.rb +4 -3
  45. data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
  46. data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
  47. data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
  48. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
  49. data/lib/concurrent/executor/safe_task_executor.rb +5 -4
  50. data/lib/concurrent/executor/serialized_execution.rb +22 -18
  51. data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
  52. data/lib/concurrent/executor/single_thread_executor.rb +32 -21
  53. data/lib/concurrent/executor/thread_pool_executor.rb +73 -60
  54. data/lib/concurrent/executor/timer_set.rb +96 -84
  55. data/lib/concurrent/executors.rb +1 -1
  56. data/lib/concurrent/future.rb +71 -38
  57. data/lib/concurrent/immutable_struct.rb +89 -0
  58. data/lib/concurrent/ivar.rb +152 -60
  59. data/lib/concurrent/lazy_register.rb +40 -20
  60. data/lib/concurrent/maybe.rb +226 -0
  61. data/lib/concurrent/mutable_struct.rb +227 -0
  62. data/lib/concurrent/mvar.rb +44 -43
  63. data/lib/concurrent/promise.rb +229 -136
  64. data/lib/concurrent/scheduled_task.rb +341 -43
  65. data/lib/concurrent/settable_struct.rb +127 -0
  66. data/lib/concurrent/synchronization.rb +17 -0
  67. data/lib/concurrent/synchronization/abstract_object.rb +163 -0
  68. data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
  69. data/lib/concurrent/synchronization/condition.rb +53 -0
  70. data/lib/concurrent/synchronization/java_object.rb +34 -0
  71. data/lib/concurrent/synchronization/lock.rb +32 -0
  72. data/lib/concurrent/synchronization/monitor_object.rb +26 -0
  73. data/lib/concurrent/synchronization/mutex_object.rb +43 -0
  74. data/lib/concurrent/synchronization/object.rb +78 -0
  75. data/lib/concurrent/synchronization/rbx_object.rb +75 -0
  76. data/lib/concurrent/timer_task.rb +92 -103
  77. data/lib/concurrent/tvar.rb +42 -38
  78. data/lib/concurrent/utilities.rb +3 -1
  79. data/lib/concurrent/utility/at_exit.rb +97 -0
  80. data/lib/concurrent/utility/engine.rb +44 -0
  81. data/lib/concurrent/utility/monotonic_time.rb +59 -0
  82. data/lib/concurrent/utility/native_extension_loader.rb +56 -0
  83. data/lib/concurrent/utility/processor_counter.rb +156 -0
  84. data/lib/concurrent/utility/timeout.rb +18 -14
  85. data/lib/concurrent/utility/timer.rb +11 -6
  86. data/lib/concurrent/version.rb +2 -1
  87. data/lib/concurrent_ruby.rb +1 -0
  88. data/lib/concurrent_ruby_ext.jar +0 -0
  89. metadata +46 -66
  90. data/lib/concurrent/actor.rb +0 -103
  91. data/lib/concurrent/actor/behaviour.rb +0 -70
  92. data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
  93. data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
  94. data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
  95. data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
  96. data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
  97. data/lib/concurrent/actor/behaviour/linking.rb +0 -45
  98. data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
  99. data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
  100. data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
  101. data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
  102. data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
  103. data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
  104. data/lib/concurrent/actor/behaviour/termination.rb +0 -54
  105. data/lib/concurrent/actor/context.rb +0 -154
  106. data/lib/concurrent/actor/core.rb +0 -217
  107. data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
  108. data/lib/concurrent/actor/envelope.rb +0 -41
  109. data/lib/concurrent/actor/errors.rb +0 -27
  110. data/lib/concurrent/actor/internal_delegations.rb +0 -49
  111. data/lib/concurrent/actor/public_delegations.rb +0 -40
  112. data/lib/concurrent/actor/reference.rb +0 -81
  113. data/lib/concurrent/actor/root.rb +0 -37
  114. data/lib/concurrent/actor/type_check.rb +0 -48
  115. data/lib/concurrent/actor/utils.rb +0 -10
  116. data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
  117. data/lib/concurrent/actor/utils/balancer.rb +0 -42
  118. data/lib/concurrent/actor/utils/broadcast.rb +0 -52
  119. data/lib/concurrent/actor/utils/pool.rb +0 -59
  120. data/lib/concurrent/actress.rb +0 -3
  121. data/lib/concurrent/agent.rb +0 -209
  122. data/lib/concurrent/atomic.rb +0 -92
  123. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
  124. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
  125. data/lib/concurrent/atomic/synchronization.rb +0 -51
  126. data/lib/concurrent/channel/buffered_channel.rb +0 -85
  127. data/lib/concurrent/channel/channel.rb +0 -41
  128. data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
  129. data/lib/concurrent/channel/waitable_list.rb +0 -40
  130. data/lib/concurrent/channels.rb +0 -5
  131. data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
  132. data/lib/concurrent/collection/ring_buffer.rb +0 -59
  133. data/lib/concurrent/collections.rb +0 -3
  134. data/lib/concurrent/dereferenceable.rb +0 -108
  135. data/lib/concurrent/executor/java_cached_thread_pool.rb +0 -32
  136. data/lib/concurrent/executor/java_fixed_thread_pool.rb +0 -31
  137. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +0 -29
  138. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +0 -32
  139. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
  140. data/lib/concurrent/logging.rb +0 -20
  141. data/lib/concurrent/obligation.rb +0 -171
  142. data/lib/concurrent/observable.rb +0 -73
  143. data/lib/concurrent/options_parser.rb +0 -48
  144. data/lib/concurrent/utility/processor_count.rb +0 -152
  145. 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
@@ -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(StandardError)
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(StandardError)
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(StandardError)
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(StandardError)
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(StandardError)
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(StandardError)
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(StandardError)
40
+ TimeoutError = Class.new(Error)
29
41
 
30
42
  end
@@ -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 thread. nil (default value) means no timeout
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/executor/ruby_cached_thread_pool'
1
+ require 'concurrent/utility/engine'
2
+ require 'concurrent/executor/thread_pool_executor'
2
3
 
3
4
  module Concurrent
4
5
 
5
- if RUBY_PLATFORM == 'java'
6
- require 'concurrent/executor/java_cached_thread_pool'
7
- # @!macro [attach] cached_thread_pool
8
- # A thread pool that dynamically grows and shrinks to fit the current workload.
9
- # New threads are created as needed, existing threads are reused, and threads
10
- # that remain idle for too long are killed and removed from the pool. These
11
- # pools are particularly suited to applications that perform a high volume of
12
- # short-lived tasks.
13
- #
14
- # On creation a `CachedThreadPool` has zero running threads. New threads are
15
- # created on the pool as new operations are `#post`. The size of the pool
16
- # will grow until `#max_length` threads are in the pool or until the number
17
- # of threads exceeds the number of running and pending operations. When a new
18
- # operation is post to the pool the first available idle thread will be tasked
19
- # with the new operation.
20
- #
21
- # Should a thread crash for any reason the thread will immediately be removed
22
- # from the pool. Similarly, threads which remain idle for an extended period
23
- # of time will be killed and reclaimed. Thus these thread pools are very
24
- # efficient at reclaiming unused resources.
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
- # The API and behavior of this class are based on Java's `CachedThreadPool`
31
+ # Create a new thread pool.
27
32
  #
28
- # @note When running on the JVM (JRuby) this class will inherit from `JavaCachedThreadPool`.
29
- # On all other platforms it will inherit from `RubyCachedThreadPool`.
33
+ # @param [Hash] opts the options defining pool behavior.
34
+ # @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy
30
35
  #
31
- # @see Concurrent::RubyCachedThreadPool
32
- # @see Concurrent::JavaCachedThreadPool
36
+ # @raise [ArgumentError] if `fallback_policy` is not a known policy
33
37
  #
34
- # @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
35
- # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html
36
- # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
37
- class CachedThreadPool < JavaCachedThreadPool
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
- else
40
- # @!macro cached_thread_pool
41
- class CachedThreadPool < RubyCachedThreadPool
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/errors'
2
- require 'concurrent/logging'
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
- # The policy defining how rejected tasks (tasks received once the
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
- # @!macro [attach] executor_module_method_can_overflow_question
10
+ # Get the requested `Executor` based on the values set in the options hash.
15
11
  #
16
- # Does the task queue have a maximum size?
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
- # @return [Boolean] True if the task queue has a maximum size else false.
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 handle_fallback(*args)
32
- case @fallback_policy
33
- when :abort
34
- raise RejectedExecutionError
35
- when :discard
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
- false
27
+ executor(opts[:executor])
282
28
  end
283
- end
284
-
285
- # @!macro executor_method_shutdown_question
286
- def shutdown?
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
- # @!macro executor_method_shutdown
301
- def shutdown
302
- @executor.shutdown
303
- nil
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
- # @!macro executor_method_kill
307
- def kill
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
- protected
313
-
314
- def set_shutdown_hook
315
- # without this the process may fail to exit
316
- at_exit { self.kill }
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