concurrent-ruby 0.8.0 → 0.9.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -2
  3. data/README.md +103 -54
  4. data/lib/concurrent.rb +34 -14
  5. data/lib/concurrent/async.rb +164 -50
  6. data/lib/concurrent/atom.rb +171 -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 +3 -0
  19. data/lib/concurrent/atomic_reference/jruby.rb +6 -3
  20. data/lib/concurrent/atomic_reference/mutex_atomic.rb +10 -32
  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 +27 -0
  29. data/lib/concurrent/concern/dereferenceable.rb +88 -0
  30. data/lib/concurrent/concern/logging.rb +25 -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 +226 -112
  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 +10 -0
  38. data/lib/concurrent/exchanger.rb +25 -1
  39. data/lib/concurrent/executor/cached_thread_pool.rb +46 -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 +206 -26
  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_cached_thread_pool.rb +18 -16
  46. data/lib/concurrent/executor/java_fixed_thread_pool.rb +11 -18
  47. data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
  48. data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
  49. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +9 -18
  50. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +10 -21
  51. data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
  52. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
  53. data/lib/concurrent/executor/safe_task_executor.rb +5 -4
  54. data/lib/concurrent/executor/serialized_execution.rb +22 -18
  55. data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
  56. data/lib/concurrent/executor/single_thread_executor.rb +32 -21
  57. data/lib/concurrent/executor/thread_pool_executor.rb +72 -60
  58. data/lib/concurrent/executor/timer_set.rb +96 -84
  59. data/lib/concurrent/executors.rb +1 -1
  60. data/lib/concurrent/future.rb +70 -38
  61. data/lib/concurrent/immutable_struct.rb +89 -0
  62. data/lib/concurrent/ivar.rb +152 -60
  63. data/lib/concurrent/lazy_register.rb +40 -20
  64. data/lib/concurrent/maybe.rb +226 -0
  65. data/lib/concurrent/mutable_struct.rb +227 -0
  66. data/lib/concurrent/mvar.rb +44 -43
  67. data/lib/concurrent/promise.rb +208 -134
  68. data/lib/concurrent/scheduled_task.rb +339 -43
  69. data/lib/concurrent/settable_struct.rb +127 -0
  70. data/lib/concurrent/synchronization.rb +17 -0
  71. data/lib/concurrent/synchronization/abstract_object.rb +163 -0
  72. data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
  73. data/lib/concurrent/synchronization/condition.rb +53 -0
  74. data/lib/concurrent/synchronization/java_object.rb +35 -0
  75. data/lib/concurrent/synchronization/lock.rb +32 -0
  76. data/lib/concurrent/synchronization/monitor_object.rb +24 -0
  77. data/lib/concurrent/synchronization/mutex_object.rb +43 -0
  78. data/lib/concurrent/synchronization/object.rb +78 -0
  79. data/lib/concurrent/synchronization/rbx_object.rb +75 -0
  80. data/lib/concurrent/timer_task.rb +87 -100
  81. data/lib/concurrent/tvar.rb +42 -38
  82. data/lib/concurrent/utilities.rb +3 -1
  83. data/lib/concurrent/utility/at_exit.rb +97 -0
  84. data/lib/concurrent/utility/engine.rb +40 -0
  85. data/lib/concurrent/utility/monotonic_time.rb +59 -0
  86. data/lib/concurrent/utility/native_extension_loader.rb +56 -0
  87. data/lib/concurrent/utility/processor_counter.rb +156 -0
  88. data/lib/concurrent/utility/timeout.rb +18 -14
  89. data/lib/concurrent/utility/timer.rb +11 -6
  90. data/lib/concurrent/version.rb +2 -1
  91. data/lib/concurrent_ruby.rb +1 -0
  92. metadata +47 -83
  93. data/lib/concurrent/actor.rb +0 -103
  94. data/lib/concurrent/actor/behaviour.rb +0 -70
  95. data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
  96. data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
  97. data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
  98. data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
  99. data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
  100. data/lib/concurrent/actor/behaviour/linking.rb +0 -45
  101. data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
  102. data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
  103. data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
  104. data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
  105. data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
  106. data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
  107. data/lib/concurrent/actor/behaviour/termination.rb +0 -54
  108. data/lib/concurrent/actor/context.rb +0 -154
  109. data/lib/concurrent/actor/core.rb +0 -217
  110. data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
  111. data/lib/concurrent/actor/envelope.rb +0 -41
  112. data/lib/concurrent/actor/errors.rb +0 -27
  113. data/lib/concurrent/actor/internal_delegations.rb +0 -49
  114. data/lib/concurrent/actor/public_delegations.rb +0 -40
  115. data/lib/concurrent/actor/reference.rb +0 -81
  116. data/lib/concurrent/actor/root.rb +0 -37
  117. data/lib/concurrent/actor/type_check.rb +0 -48
  118. data/lib/concurrent/actor/utils.rb +0 -10
  119. data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
  120. data/lib/concurrent/actor/utils/balancer.rb +0 -42
  121. data/lib/concurrent/actor/utils/broadcast.rb +0 -52
  122. data/lib/concurrent/actor/utils/pool.rb +0 -59
  123. data/lib/concurrent/actress.rb +0 -3
  124. data/lib/concurrent/agent.rb +0 -209
  125. data/lib/concurrent/atomic.rb +0 -92
  126. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
  127. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
  128. data/lib/concurrent/atomic/synchronization.rb +0 -51
  129. data/lib/concurrent/channel/buffered_channel.rb +0 -85
  130. data/lib/concurrent/channel/channel.rb +0 -41
  131. data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
  132. data/lib/concurrent/channel/waitable_list.rb +0 -40
  133. data/lib/concurrent/channels.rb +0 -5
  134. data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
  135. data/lib/concurrent/collection/ring_buffer.rb +0 -59
  136. data/lib/concurrent/collections.rb +0 -3
  137. data/lib/concurrent/dereferenceable.rb +0 -108
  138. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
  139. data/lib/concurrent/logging.rb +0 -20
  140. data/lib/concurrent/obligation.rb +0 -171
  141. data/lib/concurrent/observable.rb +0 -73
  142. data/lib/concurrent/options_parser.rb +0 -52
  143. data/lib/concurrent/utility/processor_count.rb +0 -152
  144. 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
25
+ # change frequently. They are not expected to keep backward compatibility.
26
+ # They may also lack tests and documentation. Use with caution.
27
+ module Edge
28
+
29
+ end
30
+ end
@@ -3,10 +3,16 @@ module Concurrent
3
3
  # Raised when errors occur during configuration.
4
4
  ConfigurationError = Class.new(StandardError)
5
5
 
6
+ # Raised when an asynchronous operation is cancelled before execution.
7
+ CancelledOperationError = Class.new(StandardError)
8
+
6
9
  # Raised when a lifecycle method (such as `stop`) is called in an improper
7
10
  # sequence or when the object is in an inappropriate state.
8
11
  LifecycleError = Class.new(StandardError)
9
12
 
13
+ # Raised when an attempt is made to violate an immutability guarantee.
14
+ ImmutabilityError = Class.new(StandardError)
15
+
10
16
  # Raised when an object's methods are called when it has not been
11
17
  # properly initialized.
12
18
  InitializationError = Class.new(StandardError)
@@ -24,6 +30,10 @@ module Concurrent
24
30
  # possibly because of a reject policy or other internal error.
25
31
  RejectedExecutionError = Class.new(StandardError)
26
32
 
33
+ # Raised when any finite resource, such as a lock counter, exceeds its
34
+ # maximum limit/threshold.
35
+ ResourceLimitError = Class.new(StandardError)
36
+
27
37
  # Raised when an operation times out.
28
38
  TimeoutError = Class.new(StandardError)
29
39
 
@@ -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)
@@ -2,43 +2,56 @@ require 'concurrent/executor/ruby_cached_thread_pool'
2
2
 
3
3
  module Concurrent
4
4
 
5
- if RUBY_PLATFORM == 'java'
5
+ if Concurrent.on_jruby?
6
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.
7
+ end
8
+
9
+ CachedThreadPoolImplementation = case
10
+ when Concurrent.on_jruby?
11
+ JavaCachedThreadPool
12
+ else
13
+ RubyCachedThreadPool
14
+ end
15
+ private_constant :CachedThreadPoolImplementation
16
+
17
+ # @!macro [attach] cached_thread_pool
18
+ #
19
+ # A thread pool that dynamically grows and shrinks to fit the current workload.
20
+ # New threads are created as needed, existing threads are reused, and threads
21
+ # that remain idle for too long are killed and removed from the pool. These
22
+ # pools are particularly suited to applications that perform a high volume of
23
+ # short-lived tasks.
24
+ #
25
+ # On creation a `CachedThreadPool` has zero running threads. New threads are
26
+ # created on the pool as new operations are `#post`. The size of the pool
27
+ # will grow until `#max_length` threads are in the pool or until the number
28
+ # of threads exceeds the number of running and pending operations. When a new
29
+ # operation is post to the pool the first available idle thread will be tasked
30
+ # with the new operation.
31
+ #
32
+ # Should a thread crash for any reason the thread will immediately be removed
33
+ # from the pool. Similarly, threads which remain idle for an extended period
34
+ # of time will be killed and reclaimed. Thus these thread pools are very
35
+ # efficient at reclaiming unused resources.
36
+ #
37
+ # The API and behavior of this class are based on Java's `CachedThreadPool`
38
+ #
39
+ # @!macro thread_pool_options
40
+ # @!macro thread_pool_executor_public_api
41
+ class CachedThreadPool < CachedThreadPoolImplementation
42
+
43
+ # @!macro [new] cached_thread_pool_method_initialize
25
44
  #
26
- # The API and behavior of this class are based on Java's `CachedThreadPool`
45
+ # Create a new thread pool.
27
46
  #
28
- # @note When running on the JVM (JRuby) this class will inherit from `JavaCachedThreadPool`.
29
- # On all other platforms it will inherit from `RubyCachedThreadPool`.
47
+ # @param [Hash] opts the options defining pool behavior.
48
+ # @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy
30
49
  #
31
- # @see Concurrent::RubyCachedThreadPool
32
- # @see Concurrent::JavaCachedThreadPool
50
+ # @raise [ArgumentError] if `fallback_policy` is not a known policy
33
51
  #
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
- end
39
- else
40
- # @!macro cached_thread_pool
41
- class CachedThreadPool < RubyCachedThreadPool
42
- end
52
+ # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool--
53
+
54
+ # @!method initialize(opts = {})
55
+ # @!macro cached_thread_pool_method_initialize
43
56
  end
44
57
  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