concurrent-ruby 0.9.2 → 1.0.0.pre1
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 +15 -1
- data/README.md +67 -68
- data/lib/concurrent.rb +14 -1
- data/lib/concurrent/array.rb +38 -0
- data/lib/concurrent/async.rb +0 -17
- data/lib/concurrent/atomic/abstract_thread_local_var.rb +40 -0
- data/lib/concurrent/atomic/atomic_boolean.rb +81 -118
- data/lib/concurrent/atomic/atomic_fixnum.rb +98 -162
- data/lib/concurrent/atomic/atomic_reference.rb +0 -7
- data/lib/concurrent/atomic/count_down_latch.rb +62 -103
- data/lib/concurrent/atomic/cyclic_barrier.rb +2 -0
- data/lib/concurrent/atomic/java_count_down_latch.rb +39 -0
- data/lib/concurrent/atomic/java_thread_local_var.rb +50 -0
- data/lib/concurrent/atomic/mutex_atomic_boolean.rb +60 -0
- data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +91 -0
- data/lib/concurrent/atomic/mutex_count_down_latch.rb +43 -0
- data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
- data/lib/concurrent/atomic/ruby_thread_local_var.rb +172 -0
- data/lib/concurrent/atomic/semaphore.rb +84 -178
- data/lib/concurrent/atomic/thread_local_var.rb +63 -294
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +14 -8
- data/lib/concurrent/atomics.rb +0 -33
- data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
- data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +921 -0
- data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
- data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +142 -0
- data/lib/concurrent/collection/map/synchronized_map_backend.rb +86 -0
- data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
- data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
- data/lib/concurrent/concern/logging.rb +1 -1
- data/lib/concurrent/concern/obligation.rb +0 -12
- data/lib/concurrent/configuration.rb +18 -148
- data/lib/concurrent/delay.rb +5 -4
- data/lib/concurrent/exchanger.rb +327 -41
- data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
- data/lib/concurrent/executor/executor.rb +4 -29
- data/lib/concurrent/executor/executor_service.rb +23 -359
- data/lib/concurrent/executor/immediate_executor.rb +3 -2
- data/lib/concurrent/executor/java_executor_service.rb +100 -0
- data/lib/concurrent/executor/java_single_thread_executor.rb +3 -2
- data/lib/concurrent/executor/java_thread_pool_executor.rb +3 -4
- data/lib/concurrent/executor/ruby_executor_service.rb +72 -0
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +7 -5
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +3 -11
- data/lib/concurrent/executor/safe_task_executor.rb +1 -1
- data/lib/concurrent/executor/serial_executor_service.rb +34 -0
- data/lib/concurrent/executor/serialized_execution.rb +8 -31
- data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
- data/lib/concurrent/executor/simple_executor_service.rb +1 -10
- data/lib/concurrent/executor/timer_set.rb +4 -8
- data/lib/concurrent/executors.rb +13 -2
- data/lib/concurrent/future.rb +2 -2
- data/lib/concurrent/hash.rb +35 -0
- data/lib/concurrent/ivar.rb +9 -14
- data/lib/concurrent/map.rb +178 -0
- data/lib/concurrent/promise.rb +2 -2
- data/lib/concurrent/scheduled_task.rb +9 -69
- data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
- data/lib/concurrent/thread_safe/util.rb +23 -0
- data/lib/concurrent/thread_safe/util/adder.rb +71 -0
- data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +28 -0
- data/lib/concurrent/thread_safe/util/cheap_lockable.rb +115 -0
- data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +37 -0
- data/lib/concurrent/thread_safe/util/striped64.rb +236 -0
- data/lib/concurrent/thread_safe/util/volatile.rb +73 -0
- data/lib/concurrent/thread_safe/util/xor_shift_random.rb +48 -0
- data/lib/concurrent/timer_task.rb +3 -3
- data/lib/concurrent/tuple.rb +86 -0
- data/lib/concurrent/version.rb +2 -2
- metadata +37 -10
- data/lib/concurrent/atomic/condition.rb +0 -78
- data/lib/concurrent/collection/priority_queue.rb +0 -360
- data/lib/concurrent/utilities.rb +0 -5
- data/lib/concurrent/utility/timeout.rb +0 -39
- data/lib/concurrent/utility/timer.rb +0 -26
- data/lib/concurrent_ruby.rb +0 -2
@@ -89,7 +89,7 @@ module Concurrent
|
|
89
89
|
@stopped.wait(timeout)
|
90
90
|
end
|
91
91
|
|
92
|
-
|
92
|
+
private
|
93
93
|
|
94
94
|
def ns_initialize
|
95
95
|
@running = Concurrent::AtomicBoolean.new(true)
|
@@ -97,13 +97,4 @@ module Concurrent
|
|
97
97
|
@count = Concurrent::AtomicFixnum.new(0)
|
98
98
|
end
|
99
99
|
end
|
100
|
-
|
101
|
-
# @deprecated
|
102
|
-
class PerThreadExecutor < SimpleExecutorService
|
103
|
-
|
104
|
-
def initialize
|
105
|
-
deprecated 'use SimpleExecutorService instead'
|
106
|
-
super
|
107
|
-
end
|
108
|
-
end
|
109
100
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'concurrent/scheduled_task'
|
2
2
|
require 'concurrent/atomic/event'
|
3
|
-
require 'concurrent/collection/
|
4
|
-
require 'concurrent/concern/deprecation'
|
3
|
+
require 'concurrent/collection/non_concurrent_priority_queue'
|
5
4
|
require 'concurrent/executor/executor_service'
|
6
5
|
require 'concurrent/executor/single_thread_executor'
|
7
6
|
|
@@ -16,7 +15,6 @@ module Concurrent
|
|
16
15
|
#
|
17
16
|
# @!macro monotonic_clock_warning
|
18
17
|
class TimerSet < RubyExecutorService
|
19
|
-
extend Concern::Deprecation
|
20
18
|
|
21
19
|
# Create a new set of timed tasks.
|
22
20
|
#
|
@@ -45,8 +43,6 @@ module Concurrent
|
|
45
43
|
#
|
46
44
|
# @raise [ArgumentError] if the intended execution time is not in the future.
|
47
45
|
# @raise [ArgumentError] if no block is given.
|
48
|
-
#
|
49
|
-
# @!macro deprecated_scheduling_by_clock_time
|
50
46
|
def post(delay, *args, &task)
|
51
47
|
raise ArgumentError.new('no block given') unless block_given?
|
52
48
|
return false unless running?
|
@@ -69,14 +65,14 @@ module Concurrent
|
|
69
65
|
|
70
66
|
private :<<
|
71
67
|
|
72
|
-
|
68
|
+
private
|
73
69
|
|
74
70
|
# Initialize the object.
|
75
71
|
#
|
76
72
|
# @param [Hash] opts the options to create the object with.
|
77
73
|
# @!visibility private
|
78
74
|
def ns_initialize(opts)
|
79
|
-
@queue = Collection::
|
75
|
+
@queue = Collection::NonConcurrentPriorityQueue.new(order: :min)
|
80
76
|
@task_executor = Executor.executor_from_options(opts) || Concurrent.global_io_executor
|
81
77
|
@timer_executor = SingleThreadExecutor.new
|
82
78
|
@condition = Event.new
|
@@ -122,7 +118,7 @@ module Concurrent
|
|
122
118
|
# `ExecutorServic` callback called during shutdown.
|
123
119
|
#
|
124
120
|
# @!visibility private
|
125
|
-
def
|
121
|
+
def ns_shutdown_execution
|
126
122
|
@queue.clear
|
127
123
|
@timer_executor.kill
|
128
124
|
stopped_event.set
|
data/lib/concurrent/executors.rb
CHANGED
@@ -1,10 +1,21 @@
|
|
1
|
+
require 'concurrent/executor/abstract_executor_service'
|
1
2
|
require 'concurrent/executor/cached_thread_pool'
|
3
|
+
require 'concurrent/executor/executor'
|
4
|
+
require 'concurrent/executor/executor_service'
|
2
5
|
require 'concurrent/executor/fixed_thread_pool'
|
3
6
|
require 'concurrent/executor/immediate_executor'
|
4
7
|
require 'concurrent/executor/indirect_immediate_executor'
|
8
|
+
require 'concurrent/executor/java_executor_service'
|
9
|
+
require 'concurrent/executor/java_single_thread_executor'
|
10
|
+
require 'concurrent/executor/java_thread_pool_executor'
|
11
|
+
require 'concurrent/executor/ruby_executor_service'
|
12
|
+
require 'concurrent/executor/ruby_single_thread_executor'
|
13
|
+
require 'concurrent/executor/ruby_thread_pool_executor'
|
14
|
+
require 'concurrent/executor/cached_thread_pool'
|
5
15
|
require 'concurrent/executor/safe_task_executor'
|
6
|
-
require 'concurrent/executor/
|
16
|
+
require 'concurrent/executor/serial_executor_service'
|
17
|
+
require 'concurrent/executor/serialized_execution'
|
18
|
+
require 'concurrent/executor/serialized_execution_delegator'
|
7
19
|
require 'concurrent/executor/single_thread_executor'
|
8
20
|
require 'concurrent/executor/thread_pool_executor'
|
9
21
|
require 'concurrent/executor/timer_set'
|
10
|
-
require 'concurrent/executor/serialized_execution'
|
data/lib/concurrent/future.rb
CHANGED
@@ -27,7 +27,7 @@ module Concurrent
|
|
27
27
|
# @raise [ArgumentError] if no block is given
|
28
28
|
def initialize(opts = {}, &block)
|
29
29
|
raise ArgumentError.new('no block given') unless block_given?
|
30
|
-
super(
|
30
|
+
super(NULL, opts.merge(__task_from_block__: block), &nil)
|
31
31
|
end
|
32
32
|
|
33
33
|
# Execute an `:unscheduled` `Future`. Immediately sets the state to `:pending` and
|
@@ -74,7 +74,7 @@ module Concurrent
|
|
74
74
|
end
|
75
75
|
|
76
76
|
# @!macro ivar_set_method
|
77
|
-
def set(value =
|
77
|
+
def set(value = NULL, &block)
|
78
78
|
check_for_block_or_value!(block_given?, value)
|
79
79
|
synchronize do
|
80
80
|
if @state != :unscheduled
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'concurrent/utility/engine'
|
2
|
+
require 'concurrent/thread_safe/util'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
if Concurrent.on_cruby?
|
6
|
+
|
7
|
+
# @!macro [attach] concurrent_hash
|
8
|
+
#
|
9
|
+
# A thread-safe subclass of Hash. This version locks against the object
|
10
|
+
# itself for every method call, ensuring only one thread can be reading
|
11
|
+
# or writing at a time. This includes iteration methods like `#each`.
|
12
|
+
#
|
13
|
+
# @see http://ruby-doc.org/core-2.2.0/Hash.html Ruby standard library `Hash`
|
14
|
+
class Hash < ::Hash;
|
15
|
+
end
|
16
|
+
|
17
|
+
elsif Concurrent.on_jruby?
|
18
|
+
require 'jruby/synchronized'
|
19
|
+
|
20
|
+
# @!macro concurrent_hash
|
21
|
+
class Hash < ::Hash
|
22
|
+
include JRuby::Synchronized
|
23
|
+
end
|
24
|
+
|
25
|
+
elsif Concurrent.on_rbx?
|
26
|
+
require 'monitor'
|
27
|
+
|
28
|
+
# @!macro concurrent_hash
|
29
|
+
class Hash < ::Hash
|
30
|
+
end
|
31
|
+
|
32
|
+
ThreadSafe::Util.make_synchronized_on_rbx Hash
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
data/lib/concurrent/ivar.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'thread'
|
2
|
-
|
3
1
|
require 'concurrent/errors'
|
4
2
|
require 'concurrent/collection/copy_on_write_observer_set'
|
5
3
|
require 'concurrent/concern/obligation'
|
@@ -49,9 +47,6 @@ module Concurrent
|
|
49
47
|
include Concern::Obligation
|
50
48
|
include Concern::Observable
|
51
49
|
|
52
|
-
# @!visibility private
|
53
|
-
NO_VALUE = Object.new # :nodoc:
|
54
|
-
|
55
50
|
# Create a new `IVar` in the `:pending` state with the (optional) initial value.
|
56
51
|
#
|
57
52
|
# @param [Object] value the initial value
|
@@ -62,8 +57,8 @@ module Concurrent
|
|
62
57
|
# returning the data
|
63
58
|
# @option opts [String] :copy_on_deref (nil) call the given `Proc` passing
|
64
59
|
# the internal value and returning the value returned from the proc
|
65
|
-
def initialize(value =
|
66
|
-
if value !=
|
60
|
+
def initialize(value = NULL, opts = {}, &block)
|
61
|
+
if value != NULL && block_given?
|
67
62
|
raise ArgumentError.new('provide only a value or a block')
|
68
63
|
end
|
69
64
|
super(&nil)
|
@@ -104,16 +99,16 @@ module Concurrent
|
|
104
99
|
|
105
100
|
# @!macro [attach] ivar_set_method
|
106
101
|
# Set the `IVar` to a value and wake or notify all threads waiting on it.
|
107
|
-
#
|
102
|
+
#
|
108
103
|
# @!macro [attach] ivar_set_parameters_and_exceptions
|
109
104
|
# @param [Object] value the value to store in the `IVar`
|
110
105
|
# @yield A block operation to use for setting the value
|
111
106
|
# @raise [ArgumentError] if both a value and a block are given
|
112
107
|
# @raise [Concurrent::MultipleAssignmentError] if the `IVar` has already
|
113
108
|
# been set or otherwise completed
|
114
|
-
#
|
109
|
+
#
|
115
110
|
# @return [IVar] self
|
116
|
-
def set(value =
|
111
|
+
def set(value = NULL)
|
117
112
|
check_for_block_or_value!(block_given?, value)
|
118
113
|
raise MultipleAssignmentError unless compare_and_set_state(:processing, :pending)
|
119
114
|
|
@@ -130,7 +125,7 @@ module Concurrent
|
|
130
125
|
|
131
126
|
# @!macro [attach] ivar_fail_method
|
132
127
|
# Set the `IVar` to failed due to some error and wake or notify all threads waiting on it.
|
133
|
-
#
|
128
|
+
#
|
134
129
|
# @param [Object] reason for the failure
|
135
130
|
# @raise [Concurrent::MultipleAssignmentError] if the `IVar` has already
|
136
131
|
# been set or otherwise completed
|
@@ -145,7 +140,7 @@ module Concurrent
|
|
145
140
|
# @!macro ivar_set_parameters_and_exceptions
|
146
141
|
#
|
147
142
|
# @return [Boolean] true if the value was set else false
|
148
|
-
def try_set(value =
|
143
|
+
def try_set(value = NULL, &block)
|
149
144
|
set(value, &block)
|
150
145
|
true
|
151
146
|
rescue MultipleAssignmentError
|
@@ -161,7 +156,7 @@ module Concurrent
|
|
161
156
|
self.observers = Collection::CopyOnWriteObserverSet.new
|
162
157
|
set_deref_options(opts)
|
163
158
|
|
164
|
-
if value ==
|
159
|
+
if value == NULL
|
165
160
|
@state = :pending
|
166
161
|
else
|
167
162
|
ns_complete_without_notification(true, value, nil)
|
@@ -204,7 +199,7 @@ module Concurrent
|
|
204
199
|
|
205
200
|
# @!visibility private
|
206
201
|
def check_for_block_or_value!(block_given, value) # :nodoc:
|
207
|
-
if (block_given && value !=
|
202
|
+
if (block_given && value != NULL) || (! block_given && value == NULL)
|
208
203
|
raise ArgumentError.new('must set with either a value or a block')
|
209
204
|
end
|
210
205
|
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
# @!visibility private
|
5
|
+
module Collection
|
6
|
+
|
7
|
+
# @!visibility private
|
8
|
+
MapImplementation = if defined?(RUBY_ENGINE)
|
9
|
+
case RUBY_ENGINE
|
10
|
+
when 'jruby'
|
11
|
+
# noinspection RubyResolve
|
12
|
+
JRubyMapBackend
|
13
|
+
when 'ruby'
|
14
|
+
require 'concurrent/collection/map/mri_map_backend'
|
15
|
+
MriMapBackend
|
16
|
+
when 'rbx'
|
17
|
+
require 'concurrent/collection/map/atomic_reference_map_backend'
|
18
|
+
AtomicReferenceMapBackend
|
19
|
+
else
|
20
|
+
warn 'Concurrent::Map: unsupported Ruby engine, using a fully synchronized Concurrent::Map implementation' if $VERBOSE
|
21
|
+
require 'concurrent/collection/map/synchronized_map_backend'
|
22
|
+
SynchronizedMapBackend
|
23
|
+
end
|
24
|
+
else
|
25
|
+
MriMapBackend
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# `Concurrent::Map` is a hash-like object and should have much better performance
|
30
|
+
# characteristics, especially under high concurrency, than `Concurrent::Hash`.
|
31
|
+
# However, `Concurrent::Map `is not strictly semantically equivalent to a ruby `Hash`
|
32
|
+
# -- for instance, it does not necessarily retain ordering by insertion time as `Hash`
|
33
|
+
# does. For most uses it should do fine though, and we recommend you consider
|
34
|
+
# `Concurrent::Map` instead of `Concurrent::Hash` for your concurrency-safe hash needs.
|
35
|
+
#
|
36
|
+
# > require 'concurrent'
|
37
|
+
# >
|
38
|
+
# > map = Concurrent::Map.new
|
39
|
+
|
40
|
+
class Map < Collection::MapImplementation
|
41
|
+
def initialize(options = nil, &block)
|
42
|
+
if options.kind_of?(::Hash)
|
43
|
+
validate_options_hash!(options)
|
44
|
+
else
|
45
|
+
options = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
super(options)
|
49
|
+
@default_proc = block
|
50
|
+
end
|
51
|
+
|
52
|
+
def [](key)
|
53
|
+
if value = super # non-falsy value is an existing mapping, return it right away
|
54
|
+
value
|
55
|
+
# re-check is done with get_or_default(key, NULL) instead of a simple !key?(key) in order to avoid a race condition, whereby by the time the current thread gets to the key?(key) call
|
56
|
+
# a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrent +nil+ value
|
57
|
+
# would be returned)
|
58
|
+
# note: nil == value check is not technically necessary
|
59
|
+
elsif @default_proc && nil == value && NULL == (value = get_or_default(key, NULL))
|
60
|
+
@default_proc.call(self, key)
|
61
|
+
else
|
62
|
+
value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
alias_method :get, :[]
|
67
|
+
alias_method :put, :[]=
|
68
|
+
|
69
|
+
def fetch(key, default_value = NULL)
|
70
|
+
if NULL != (value = get_or_default(key, NULL))
|
71
|
+
value
|
72
|
+
elsif block_given?
|
73
|
+
yield key
|
74
|
+
elsif NULL != default_value
|
75
|
+
default_value
|
76
|
+
else
|
77
|
+
raise_fetch_no_key
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def fetch_or_store(key, default_value = NULL)
|
82
|
+
fetch(key) do
|
83
|
+
put(key, block_given? ? yield(key) : (NULL == default_value ? raise_fetch_no_key : default_value))
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def put_if_absent(key, value)
|
88
|
+
computed = false
|
89
|
+
result = compute_if_absent(key) do
|
90
|
+
computed = true
|
91
|
+
value
|
92
|
+
end
|
93
|
+
computed ? nil : result
|
94
|
+
end unless method_defined?(:put_if_absent)
|
95
|
+
|
96
|
+
def value?(value)
|
97
|
+
each_value do |v|
|
98
|
+
return true if value.equal?(v)
|
99
|
+
end
|
100
|
+
false
|
101
|
+
end unless method_defined?(:value?)
|
102
|
+
|
103
|
+
def keys
|
104
|
+
arr = []
|
105
|
+
each_pair {|k, v| arr << k}
|
106
|
+
arr
|
107
|
+
end unless method_defined?(:keys)
|
108
|
+
|
109
|
+
def values
|
110
|
+
arr = []
|
111
|
+
each_pair {|k, v| arr << v}
|
112
|
+
arr
|
113
|
+
end unless method_defined?(:values)
|
114
|
+
|
115
|
+
def each_key
|
116
|
+
each_pair {|k, v| yield k}
|
117
|
+
end unless method_defined?(:each_key)
|
118
|
+
|
119
|
+
def each_value
|
120
|
+
each_pair {|k, v| yield v}
|
121
|
+
end unless method_defined?(:each_value)
|
122
|
+
|
123
|
+
def key(value)
|
124
|
+
each_pair {|k, v| return k if v == value}
|
125
|
+
nil
|
126
|
+
end unless method_defined?(:key)
|
127
|
+
alias_method :index, :key if RUBY_VERSION < '1.9'
|
128
|
+
|
129
|
+
def empty?
|
130
|
+
each_pair {|k, v| return false}
|
131
|
+
true
|
132
|
+
end unless method_defined?(:empty?)
|
133
|
+
|
134
|
+
def size
|
135
|
+
count = 0
|
136
|
+
each_pair {|k, v| count += 1}
|
137
|
+
count
|
138
|
+
end unless method_defined?(:size)
|
139
|
+
|
140
|
+
def marshal_dump
|
141
|
+
raise TypeError, "can't dump hash with default proc" if @default_proc
|
142
|
+
h = {}
|
143
|
+
each_pair {|k, v| h[k] = v}
|
144
|
+
h
|
145
|
+
end
|
146
|
+
|
147
|
+
def marshal_load(hash)
|
148
|
+
initialize
|
149
|
+
populate_from(hash)
|
150
|
+
end
|
151
|
+
|
152
|
+
undef :freeze
|
153
|
+
|
154
|
+
private
|
155
|
+
def raise_fetch_no_key
|
156
|
+
raise KeyError, 'key not found'
|
157
|
+
end
|
158
|
+
|
159
|
+
def initialize_copy(other)
|
160
|
+
super
|
161
|
+
populate_from(other)
|
162
|
+
end
|
163
|
+
|
164
|
+
def populate_from(hash)
|
165
|
+
hash.each_pair {|k, v| self[k] = v}
|
166
|
+
self
|
167
|
+
end
|
168
|
+
|
169
|
+
def validate_options_hash!(options)
|
170
|
+
if (initial_capacity = options[:initial_capacity]) && (!initial_capacity.kind_of?(Fixnum) || initial_capacity < 0)
|
171
|
+
raise ArgumentError, ":initial_capacity must be a positive Fixnum"
|
172
|
+
end
|
173
|
+
if (load_factor = options[:load_factor]) && (!load_factor.kind_of?(Numeric) || load_factor <= 0 || load_factor > 1)
|
174
|
+
raise ArgumentError, ":load_factor must be a number between 0 and 1"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
data/lib/concurrent/promise.rb
CHANGED
@@ -205,7 +205,7 @@ module Concurrent
|
|
205
205
|
# @see http://promises-aplus.github.io/promises-spec/
|
206
206
|
def initialize(opts = {}, &block)
|
207
207
|
opts.delete_if { |k, v| v.nil? }
|
208
|
-
super(
|
208
|
+
super(NULL, opts.merge(__promise_body_from_block__: block), &nil)
|
209
209
|
end
|
210
210
|
|
211
211
|
# Create a new `Promise` and fulfill it immediately.
|
@@ -254,7 +254,7 @@ module Concurrent
|
|
254
254
|
# @!macro ivar_set_method
|
255
255
|
#
|
256
256
|
# @raise [Concurrent::PromiseExecutionError] if not the root promise
|
257
|
-
def set(value =
|
257
|
+
def set(value = NULL, &block)
|
258
258
|
raise PromiseExecutionError.new('supported only on root promise') unless root?
|
259
259
|
check_for_block_or_value!(block_given?, value)
|
260
260
|
synchronize do
|
@@ -1,12 +1,11 @@
|
|
1
1
|
require 'concurrent/errors'
|
2
|
+
require 'concurrent/configuration'
|
2
3
|
require 'concurrent/ivar'
|
3
4
|
require 'concurrent/collection/copy_on_notify_observer_set'
|
4
5
|
require 'concurrent/executor/executor'
|
5
6
|
require 'concurrent/utility/monotonic_time'
|
6
|
-
require 'concurrent/concern/deprecation'
|
7
7
|
|
8
8
|
module Concurrent
|
9
|
-
include Concern::Deprecation
|
10
9
|
|
11
10
|
# `ScheduledTask` is a close relative of `Concurrent::Future` but with one
|
12
11
|
# important difference: A `Future` is set to execute as soon as possible
|
@@ -161,21 +160,17 @@ module Concurrent
|
|
161
160
|
#
|
162
161
|
# @raise [ArgumentError] When no block is given
|
163
162
|
# @raise [ArgumentError] When given a time that is in the past
|
164
|
-
#
|
165
|
-
# @!macro [attach] deprecated_scheduling_by_clock_time
|
166
|
-
#
|
167
|
-
# @note Scheduling is now based on a monotonic clock. This makes the timer much
|
168
|
-
# more accurate, but only when scheduling based on a delay interval.
|
169
|
-
# Scheduling a task based on a clock time is deprecated. It will still work
|
170
|
-
# but will not be supported in the 1.0 release.
|
171
163
|
def initialize(delay, opts = {}, &task)
|
172
164
|
raise ArgumentError.new('no block given') unless block_given?
|
173
|
-
|
165
|
+
raise ArgumentError.new('seconds must be greater than zero') if delay.to_f < 0.0
|
166
|
+
|
167
|
+
super(NULL, opts, &nil)
|
168
|
+
|
174
169
|
synchronize do
|
175
|
-
@delay = calculate_delay!(delay) # may raise exception
|
176
170
|
ns_set_state(:unscheduled)
|
177
171
|
@parent = opts.fetch(:timer_set, Concurrent.global_timer_set)
|
178
172
|
@args = get_arguments_from(opts)
|
173
|
+
@delay = delay.to_f
|
179
174
|
@task = task
|
180
175
|
@time = nil
|
181
176
|
@executor = Executor.executor_from_options(opts) || Concurrent.global_io_executor
|
@@ -190,16 +185,6 @@ module Concurrent
|
|
190
185
|
synchronize { @delay }
|
191
186
|
end
|
192
187
|
|
193
|
-
# The `delay` value given at instanciation.
|
194
|
-
#
|
195
|
-
# @return [Float] the initial delay.
|
196
|
-
#
|
197
|
-
# @deprecated use {#initial_delay} instead
|
198
|
-
def delay
|
199
|
-
deprecated_method 'delay', 'initial_delay'
|
200
|
-
initial_delay
|
201
|
-
end
|
202
|
-
|
203
188
|
# The monotonic time at which the the task is scheduled to be executed.
|
204
189
|
#
|
205
190
|
# @return [Float] the schedule time or nil if `unscheduled`
|
@@ -228,16 +213,6 @@ module Concurrent
|
|
228
213
|
synchronize { ns_check_state?(:processing) }
|
229
214
|
end
|
230
215
|
|
231
|
-
# In the task execution in progress?
|
232
|
-
#
|
233
|
-
# @return [Boolean] true if the task is in the given state else false
|
234
|
-
#
|
235
|
-
# @deprecated Use {#processing?} instead.
|
236
|
-
def in_progress?
|
237
|
-
deprecated_method 'in_progress?', 'processing?'
|
238
|
-
processing?
|
239
|
-
end
|
240
|
-
|
241
216
|
# Cancel this task and prevent it from executing. A task can only be
|
242
217
|
# cancelled if it is pending or unscheduled.
|
243
218
|
#
|
@@ -253,17 +228,6 @@ module Concurrent
|
|
253
228
|
end
|
254
229
|
end
|
255
230
|
|
256
|
-
# Cancel this task and prevent it from executing. A task can only be
|
257
|
-
# cancelled if it is `:pending` or `:unscheduled`.
|
258
|
-
#
|
259
|
-
# @return [Boolean] true if successfully cancelled else false
|
260
|
-
#
|
261
|
-
# @deprecated Use {#cancel} instead.
|
262
|
-
def stop
|
263
|
-
deprecated_method 'stop', 'cancel'
|
264
|
-
cancel
|
265
|
-
end
|
266
|
-
|
267
231
|
# Reschedule the task using the original delay and the current time.
|
268
232
|
# A task can only be reset while it is `:pending`.
|
269
233
|
#
|
@@ -281,7 +245,9 @@ module Concurrent
|
|
281
245
|
#
|
282
246
|
# @raise [ArgumentError] When given a time that is in the past
|
283
247
|
def reschedule(delay)
|
284
|
-
|
248
|
+
delay = delay.to_f
|
249
|
+
raise ArgumentError.new('seconds must be greater than zero') if delay < 0.0
|
250
|
+
synchronize{ ns_reschedule(delay) }
|
285
251
|
end
|
286
252
|
|
287
253
|
# Execute an `:unscheduled` `ScheduledTask`. Immediately sets the state to `:pending`
|
@@ -306,8 +272,6 @@ module Concurrent
|
|
306
272
|
# @return [ScheduledTask] the newly created `ScheduledTask` in the `:pending` state
|
307
273
|
#
|
308
274
|
# @raise [ArgumentError] if no block is given
|
309
|
-
#
|
310
|
-
# @!macro deprecated_scheduling_by_clock_time
|
311
275
|
def self.execute(delay, opts = {}, &task)
|
312
276
|
new(delay, opts, &task).execute
|
313
277
|
end
|
@@ -348,29 +312,5 @@ module Concurrent
|
|
348
312
|
return false unless ns_check_state?(:pending)
|
349
313
|
@parent.send(:remove_task, self) && ns_schedule(delay)
|
350
314
|
end
|
351
|
-
|
352
|
-
# Calculate the actual delay in seconds based on the given delay.
|
353
|
-
#
|
354
|
-
# @param [Float] delay the number of seconds to wait for before executing the task
|
355
|
-
#
|
356
|
-
# @return [Float] the number of seconds to delay
|
357
|
-
#
|
358
|
-
# @raise [ArgumentError] if the intended execution time is not in the future
|
359
|
-
# @raise [ArgumentError] if no block is given
|
360
|
-
#
|
361
|
-
# @!macro deprecated_scheduling_by_clock_time
|
362
|
-
#
|
363
|
-
# @!visibility private
|
364
|
-
def calculate_delay!(delay)
|
365
|
-
if delay.is_a?(Time)
|
366
|
-
deprecated 'Use an interval not a clock time; schedule is now based on a monotonic clock'
|
367
|
-
now = Time.now
|
368
|
-
raise ArgumentError.new('schedule time must be in the future') if delay <= now
|
369
|
-
delay.to_f - now.to_f
|
370
|
-
else
|
371
|
-
raise ArgumentError.new('seconds must be greater than zero') if delay.to_f < 0.0
|
372
|
-
delay.to_f
|
373
|
-
end
|
374
|
-
end
|
375
315
|
end
|
376
316
|
end
|