concurrent-ruby-edge 0.1.2 → 0.2.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/README.md +67 -68
- data/lib/concurrent/actor.rb +1 -1
- data/lib/concurrent/actor/behaviour/abstract.rb +2 -1
- data/lib/concurrent/actor/behaviour/sets_results.rb +1 -1
- data/lib/concurrent/actor/context.rb +2 -1
- data/lib/concurrent/actor/core.rb +4 -4
- data/lib/concurrent/actor/default_dead_letter_handler.rb +1 -1
- data/lib/concurrent/actor/internal_delegations.rb +0 -1
- data/lib/concurrent/actor/root.rb +1 -1
- data/lib/concurrent/actor/utils/pool.rb +1 -1
- data/lib/concurrent/agent.rb +30 -52
- data/lib/concurrent/channel/buffered_channel.rb +26 -24
- data/lib/concurrent/channel/ring_buffer.rb +1 -1
- data/lib/concurrent/edge/atomic_markable_reference.rb +1 -1
- data/lib/concurrent/edge/future.rb +3 -2
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 09cfa6d29b8c6ad451d4d5805fe16ff7fe490703
|
4
|
+
data.tar.gz: 721b15c9fa7a8c38e88c9d5f1e8597e0528386c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce588f1344ce16ab7c0d166bdc1f5c86c02c908083d7fcc10c7ead35a665af4325c1e9ccabfc925f289fdb15db1d68a4fff621d67b921b6b75f6115fc4ffc22b
|
7
|
+
data.tar.gz: 479a2bb45adde98a74aa5ced4fea11d1112ccedb64d07e5dc5783d07cf750d905888effd97d8108b3dc2b928f394055423aa5bc6b8343bc26647b62bf4422300
|
data/README.md
CHANGED
@@ -47,7 +47,7 @@
|
|
47
47
|
|
48
48
|
MRI 1.9.3, 2.0, 2.1, 2.2, JRuby (1.9 mode), and Rubinius 2.x are supported.
|
49
49
|
This gem should be fully compatible with any interpreter that is compliant with Ruby 1.9.3 or newer.
|
50
|
-
Java 8 is
|
50
|
+
Java 8 is preferred for JRuby but every Java version on which JRuby 9000 runs will be supported.
|
51
51
|
|
52
52
|
## Features & Documentation
|
53
53
|
|
@@ -62,54 +62,62 @@ This library contains a variety of concurrency abstractions at high and low leve
|
|
62
62
|
#### General-purpose Concurrency Abstractions
|
63
63
|
|
64
64
|
* [Async](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Async.html): A mixin module that provides simple asynchronous behavior to any standard class/object or object.
|
65
|
-
* [Atom](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Atom.html): A way to manage shared, synchronous, independent state.
|
66
65
|
* [Future](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Future.html): An asynchronous operation that produces a value.
|
67
66
|
* [Dataflow](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent.html#dataflow-class_method): Built on Futures, Dataflow allows you to create a task that will be scheduled when all of its data dependencies are available.
|
68
67
|
* [Promise](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promise.html): Similar to Futures, with more features.
|
69
68
|
* [ScheduledTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ScheduledTask.html): Like a Future scheduled for a specific future time.
|
70
69
|
* [TimerTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TimerTask.html): A Thread that periodically wakes up to perform work at regular intervals.
|
71
70
|
|
72
|
-
#### Thread-safe Value Objects
|
71
|
+
#### Thread-safe Value Objects, Structures, and Collections
|
72
|
+
|
73
|
+
Collection classes that were originally part of the (deprecated) `thread_safe` gem:
|
74
|
+
|
75
|
+
* [Array](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Array.html) A thread-safe subclass of Ruby's standard [Array](http://ruby-doc.org/core-2.2.0/Array.html).
|
76
|
+
* [Hash](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Hash.html) A thread-safe subclass of Ruby's standard [Hash](http://ruby-doc.org/core-2.2.0/Hash.html).
|
77
|
+
* [Map](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Map.html) A hash-like object that should have much better performance characteristics, especially under high concurrency, than `Concurrent::Hash`.
|
78
|
+
* [Tuple](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Tuple.html) A fixed size array with volatile (synchronized, thread safe) getters/setters.
|
79
|
+
|
80
|
+
Value objects inspired by other languages:
|
73
81
|
|
74
|
-
*
|
82
|
+
* [Atom](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Atom.html): A way to manage shared, synchronous, independent state.
|
83
|
+
* [Maybe](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Maybe.html) A thread-safe, immutable object representing an optional value, based on
|
75
84
|
[Haskell Data.Maybe](https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-Maybe.html).
|
76
|
-
*
|
85
|
+
* [Delay](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Delay.html) Lazy evaluation of a block yielding an immutable result. Based on Clojure's
|
77
86
|
[delay](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Delay.html).
|
78
87
|
|
79
|
-
|
88
|
+
Structure classes derived from Ruby's [Struct](http://ruby-doc.org/core-2.2.0/Struct.html):
|
89
|
+
|
90
|
+
* [ImmutableStruct](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ImmutableStruct.html) Immutable struct where values are set at construction and cannot be changed later.
|
91
|
+
* [MutableStruct](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MutableStruct.html) Synchronized, mutable struct where values can be safely changed at any time.
|
92
|
+
* [SettableStruct](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/SettableStruct.html) Synchronized, write-once struct where values can be set at most once, either at construction or any time thereafter.
|
80
93
|
|
81
|
-
|
94
|
+
Thread-safe variables:
|
82
95
|
|
83
|
-
*
|
84
|
-
*
|
85
|
-
*
|
96
|
+
* [AtomicBoolean](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/AtomicBoolean.html) A boolean value that can be updated atomically.
|
97
|
+
* [AtomicFixnum](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/AtomicFixnum.html) A numeric value that can be updated atomically.
|
98
|
+
* [AtomicReference](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MutexAtomic.html) An object reference that may be updated atomically.
|
99
|
+
* [ThreadLocalVar](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ThreadLocalVar.html) A variable where the value is different for each thread.
|
86
100
|
|
87
101
|
#### Java-inspired ThreadPools and Other Executors
|
88
102
|
|
89
|
-
* See [
|
103
|
+
* See the [thread pool](http://ruby-concurrency.github.io/concurrent-ruby/file.thread_pools.html) overview, which also contains a list of other Executors available.
|
90
104
|
|
91
105
|
#### Thread Synchronization Classes and Algorithms
|
92
106
|
|
93
|
-
* [CountdownLatch](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CountDownLatch.html)
|
94
|
-
* [CyclicBarrier](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CyclicBarrier.html)
|
95
|
-
* [Event](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Event.html)
|
96
|
-
* [
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
* [
|
101
|
-
* [
|
102
|
-
* [
|
103
|
-
* [I-Structures](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/IVar.html) (IVar)
|
104
|
-
* [M-Structures](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MVar.html) (MVar)
|
105
|
-
* [Thread-local variables](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ThreadLocalVar.html)
|
106
|
-
* [Software transactional memory](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TVar.html) (TVar)
|
107
|
-
* [ReadWriteLock](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ReadWriteLock.html)
|
108
|
-
* [ReentrantReadWriteLock](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ReentrantReadWriteLock.html)
|
107
|
+
* [CountdownLatch](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CountDownLatch.html) A synchronization object that allows one thread to wait on multiple other threads.
|
108
|
+
* [CyclicBarrier](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CyclicBarrier.html) A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.
|
109
|
+
* [Event](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Event.html) Old school kernel-style event.
|
110
|
+
* [Exchanger](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Exchanger.html)
|
111
|
+
* [I-Structure](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/IVar.html) (IVar) Similar to a "future" but can be manually assigned once, after which it becomes immutable.
|
112
|
+
* [M-Structure](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MVar.html) (MVar) A synchronized single element container.
|
113
|
+
* [ReadWriteLock](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ReadWriteLock.html) A lock that supports multiple readers but only one writer.
|
114
|
+
* [ReentrantReadWriteLock](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ReentrantReadWriteLock.html) A read/write lock with reentrant and upgrade features.
|
115
|
+
* [Semaphore](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Semaphore.html) A counting-based locking mechanism that uses permits.
|
116
|
+
* [Software transactional memory](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TVar.html) (TVar) A transactional variable - a single-element container that is used as part of a transaction.
|
109
117
|
|
110
118
|
### Edge Features
|
111
119
|
|
112
|
-
These are available in the `concurrent-ruby-edge` companion gem
|
120
|
+
These are available in the `concurrent-ruby-edge` companion gem.
|
113
121
|
|
114
122
|
These features are under active development and may change frequently. They are expected not to
|
115
123
|
keep backward compatibility (there may also lack tests and documentation). Semantic versions will
|
@@ -125,10 +133,9 @@ be obeyed though. Features developed in `concurrent-ruby-edge` are expected to m
|
|
125
133
|
* [Agent](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Agent.html): A single atomic value that represents an identity.
|
126
134
|
* [Channel](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Channel.html):
|
127
135
|
Communicating Sequential Processes (CSP).
|
128
|
-
* [Exchanger](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Exchanger.html)
|
129
136
|
* [LazyRegister](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/LazyRegister.html)
|
130
|
-
* [
|
131
|
-
* [
|
137
|
+
* [AtomicMarkableReference](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Edge/AtomicMarkableReference.html)
|
138
|
+
* [LockFreeLinkedSet](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Edge/LockFreeLinkedSet.html)
|
132
139
|
* [LockFreeStack](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Edge/LockFreeStack.html)
|
133
140
|
|
134
141
|
#### Statuses:
|
@@ -139,52 +146,21 @@ be obeyed though. Features developed in `concurrent-ruby-edge` are expected to m
|
|
139
146
|
- **Future/Promise Framework** - API changes; partial documentation and tests; stability good.
|
140
147
|
- **Agent** - Incomplete behaviour compared to Clojure's models; stability good.
|
141
148
|
- **Channel** - Missing documentation; limted features; stability good.
|
142
|
-
- **Exchanger** - Known race condition requiring a new implementation.
|
143
149
|
- **LazyRegister** - Missing documentation and tests.
|
144
150
|
- **AtomicMarkableReference, LockFreeLinkedSet, LockFreeStack** - Needs real world battle testing
|
145
151
|
|
146
152
|
## Usage
|
147
153
|
|
148
|
-
|
154
|
+
Everything within this gem can be loaded simply by requiring it:
|
149
155
|
|
150
156
|
```ruby
|
151
157
|
require 'concurrent'
|
152
158
|
```
|
153
159
|
|
154
|
-
To
|
160
|
+
To use the tools in the Edge gem it must be required separately:
|
155
161
|
|
156
162
|
```ruby
|
157
|
-
require 'concurrent'
|
158
|
-
|
159
|
-
# groups
|
160
|
-
|
161
|
-
require 'concurrent/atomics' # atomic and thread synchronization classes
|
162
|
-
require 'concurrent/executors' # Thread pools and other executors
|
163
|
-
|
164
|
-
# individual abstractions
|
165
|
-
|
166
|
-
require 'concurrent/async' # Concurrent::Async
|
167
|
-
require 'concurrent/atom' # Concurrent::Atom
|
168
|
-
require 'concurrent/dataflow' # Concurrent::dataflow
|
169
|
-
require 'concurrent/delay' # Concurrent::Delay
|
170
|
-
require 'concurrent/future' # Concurrent::Future
|
171
|
-
require 'concurrent/immutable_struct' # Concurrent::ImmutableStruct
|
172
|
-
require 'concurrent/ivar' # Concurrent::IVar
|
173
|
-
require 'concurrent/maybe' # Concurrent::Maybe
|
174
|
-
require 'concurrent/mutable_struct' # Concurrent::MutableStruct
|
175
|
-
require 'concurrent/mvar' # Concurrent::MVar
|
176
|
-
require 'concurrent/promise' # Concurrent::Promise
|
177
|
-
require 'concurrent/scheduled_task' # Concurrent::ScheduledTask
|
178
|
-
require 'concurrent/settable_struct' # Concurrent::SettableStruct
|
179
|
-
require 'concurrent/timer_task' # Concurrent::TimerTask
|
180
|
-
require 'concurrent/tvar' # Concurrent::TVar
|
181
|
-
|
182
|
-
# experimental - available in `concurrent-ruby-edge` companion gem
|
183
|
-
|
184
|
-
require 'concurrent/actor' # Concurrent::Actor and supporting code
|
185
|
-
require 'concurrent/edge/future' # new Future Framework
|
186
|
-
require 'concurrent/agent' # Concurrent::Agent
|
187
|
-
require 'concurrent/channel ' # Concurrent::Channel and supporting code
|
163
|
+
require 'concurrent-edge'
|
188
164
|
```
|
189
165
|
|
190
166
|
If the library does not behave as expected, `Concurrent.use_stdlib_logger(Logger::DEBUG)` could help to reveal the problem.
|
@@ -203,6 +179,23 @@ gem 'concurrent-ruby'
|
|
203
179
|
|
204
180
|
and run `bundle install` from your shell.
|
205
181
|
|
182
|
+
### Edge Gem Installation
|
183
|
+
|
184
|
+
The Edge gem must be installed separately from the core gem:
|
185
|
+
|
186
|
+
```shell
|
187
|
+
gem install concurrent-ruby-edge
|
188
|
+
```
|
189
|
+
|
190
|
+
or add the following line to Gemfile:
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
gem 'concurrent-ruby-edge'
|
194
|
+
```
|
195
|
+
|
196
|
+
and run `bundle install` from your shell.
|
197
|
+
|
198
|
+
|
206
199
|
### C Extensions for MRI
|
207
200
|
|
208
201
|
Potential performance improvements may be achieved under MRI by installing optional C extensions.
|
@@ -240,7 +233,7 @@ The best practice is to depend on `concurrent-ruby` and let users to decide if t
|
|
240
233
|
|
241
234
|
All published versions of this gem (core, extension, and several platform-specific packages) are compiled,
|
242
235
|
packaged, tested, and published using an open, [automated process](https://github.com/ruby-concurrency/rake-compiler-dev-box).
|
243
|
-
This process can also be used to create pre-compiled binaries of the extension gem for
|
236
|
+
This process can also be used to create pre-compiled binaries of the extension gem for virtually
|
244
237
|
any platform. *Documentation is forthcoming...*
|
245
238
|
|
246
239
|
```
|
@@ -272,11 +265,17 @@ bundle exec rake compile # Compile all the extensions
|
|
272
265
|
## Maintainers
|
273
266
|
|
274
267
|
* [Jerry D'Antonio](https://github.com/jdantonio) (creator)
|
268
|
+
* [Petr Chalupa](https://github.com/pitr-ch)
|
275
269
|
* [Michele Della Torre](https://github.com/mighe)
|
276
270
|
* [Chris Seaton](https://github.com/chrisseaton)
|
277
|
-
* [Lucas Allan](https://github.com/lucasallan)
|
278
|
-
* [Petr Chalupa](https://github.com/pitr-ch)
|
279
271
|
* [Paweł Obrok](https://github.com/obrok)
|
272
|
+
* [Lucas Allan](https://github.com/lucasallan)
|
273
|
+
|
274
|
+
### Special Thanks
|
275
|
+
|
276
|
+
* [Brian Durand](https://github.com/bdurand) for the `ref` gem
|
277
|
+
* [Charles Oliver Nutter](https://github.com/headius) for the `atomic` and `thread_safe` gems
|
278
|
+
* [thedarkone](https://github.com/thedarkone) for the `thread_safe` gem
|
280
279
|
|
281
280
|
## Contributing
|
282
281
|
|
data/lib/concurrent/actor.rb
CHANGED
@@ -85,7 +85,7 @@ module Concurrent
|
|
85
85
|
# @overload to_spawn_options(opts)
|
86
86
|
# see {Core#initialize} opts
|
87
87
|
def self.to_spawn_options(*args)
|
88
|
-
if args.size == 1 && args.first.is_a?(Hash)
|
88
|
+
if args.size == 1 && args.first.is_a?(::Hash)
|
89
89
|
args.first
|
90
90
|
else
|
91
91
|
{ class: args[0],
|
@@ -6,6 +6,7 @@ module Concurrent
|
|
6
6
|
class Abstract
|
7
7
|
include TypeCheck
|
8
8
|
include InternalDelegations
|
9
|
+
include Concern::Logging
|
9
10
|
|
10
11
|
attr_reader :core, :subsequent
|
11
12
|
|
@@ -41,7 +42,7 @@ module Concurrent
|
|
41
42
|
def reject_envelope(envelope)
|
42
43
|
envelope.reject! ActorTerminated.new(reference)
|
43
44
|
dead_letter_routing << envelope unless envelope.future
|
44
|
-
log
|
45
|
+
log DEBUG, "rejected #{envelope.message} from #{envelope.sender_path}"
|
45
46
|
end
|
46
47
|
end
|
47
48
|
end
|
@@ -14,7 +14,7 @@ module Concurrent
|
|
14
14
|
result = pass envelope
|
15
15
|
if result != MESSAGE_PROCESSED && !envelope.future.nil?
|
16
16
|
envelope.future.success result
|
17
|
-
log
|
17
|
+
log DEBUG, "finished processing of #{envelope.message.inspect}"
|
18
18
|
end
|
19
19
|
nil
|
20
20
|
rescue => error
|
@@ -24,6 +24,7 @@ module Concurrent
|
|
24
24
|
class AbstractContext
|
25
25
|
include TypeCheck
|
26
26
|
include InternalDelegations
|
27
|
+
include Concern::Logging
|
27
28
|
|
28
29
|
attr_reader :core
|
29
30
|
|
@@ -128,7 +129,7 @@ module Concurrent
|
|
128
129
|
end
|
129
130
|
|
130
131
|
def self.to_spawn_options(name_or_opts, *args)
|
131
|
-
if name_or_opts.is_a? Hash
|
132
|
+
if name_or_opts.is_a? ::Hash
|
132
133
|
if name_or_opts.key?(:class) && name_or_opts[:class] != self
|
133
134
|
raise ArgumentError,
|
134
135
|
':class option is ignored when calling on context class, use Actor.spawn instead'
|
@@ -91,7 +91,7 @@ module Concurrent
|
|
91
91
|
# @param [Envelope] envelope
|
92
92
|
def on_envelope(envelope)
|
93
93
|
schedule_execution do
|
94
|
-
log
|
94
|
+
log DEBUG, "was #{envelope.future ? 'asked' : 'told'} #{envelope.message.inspect} by #{envelope.sender}"
|
95
95
|
process_envelope envelope
|
96
96
|
end
|
97
97
|
nil
|
@@ -128,7 +128,7 @@ module Concurrent
|
|
128
128
|
end
|
129
129
|
|
130
130
|
def broadcast(public, event)
|
131
|
-
log
|
131
|
+
log DEBUG, "event: #{event.inspect} (#{public ? 'public' : 'private'})"
|
132
132
|
@first_behaviour.on_event(public, event)
|
133
133
|
end
|
134
134
|
|
@@ -164,7 +164,7 @@ module Concurrent
|
|
164
164
|
private
|
165
165
|
|
166
166
|
def ns_initialize(opts, &block)
|
167
|
-
@mailbox = Array.new
|
167
|
+
@mailbox = ::Array.new
|
168
168
|
@serialized_execution = SerializedExecution.new
|
169
169
|
@children = Set.new
|
170
170
|
|
@@ -208,7 +208,7 @@ module Concurrent
|
|
208
208
|
end
|
209
209
|
|
210
210
|
def initialize_behaviours(opts)
|
211
|
-
@behaviour_definition = (Type! opts[:behaviour_definition] || @context.behaviour_definition, Array).each do |(behaviour, _)|
|
211
|
+
@behaviour_definition = (Type! opts[:behaviour_definition] || @context.behaviour_definition, ::Array).each do |(behaviour, _)|
|
212
212
|
Child! behaviour, Behaviour::Abstract
|
213
213
|
end
|
214
214
|
@behaviours = {}
|
@@ -14,7 +14,7 @@ module Concurrent
|
|
14
14
|
# to allow spawning of new actors, spawn needs to be called inside the parent Actor
|
15
15
|
def on_message(message)
|
16
16
|
case
|
17
|
-
when message.is_a?(Array) && message.first == :spawn
|
17
|
+
when message.is_a?(::Array) && message.first == :spawn
|
18
18
|
Actor.spawn message[1], &message[2]
|
19
19
|
when message == :dead_letter_routing
|
20
20
|
@dead_letter_router
|
@@ -29,7 +29,7 @@ module Concurrent
|
|
29
29
|
class Pool < RestartingContext
|
30
30
|
def initialize(size, &worker_initializer)
|
31
31
|
@balancer = Balancer.spawn name: :balancer, supervise: true
|
32
|
-
@workers = Array.new(size, &worker_initializer)
|
32
|
+
@workers = ::Array.new(size, &worker_initializer)
|
33
33
|
@workers.each do |worker|
|
34
34
|
Type! worker, Reference
|
35
35
|
@balancer << [:subscribe, worker]
|
data/lib/concurrent/agent.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
|
-
require 'thread'
|
2
1
|
require 'concurrent/collection/copy_on_write_observer_set'
|
3
2
|
require 'concurrent/concern/dereferenceable'
|
4
3
|
require 'concurrent/concern/observable'
|
5
4
|
require 'concurrent/concern/logging'
|
6
5
|
require 'concurrent/executor/executor'
|
7
|
-
require 'concurrent/
|
6
|
+
require 'concurrent/synchronization'
|
8
7
|
|
9
8
|
module Concurrent
|
10
9
|
|
@@ -81,11 +80,10 @@ module Concurrent
|
|
81
80
|
# @return [Fixnum] the maximum number of seconds before an update is cancelled
|
82
81
|
#
|
83
82
|
# @!macro edge_warning
|
84
|
-
class Agent
|
83
|
+
class Agent < Synchronization::Object
|
85
84
|
include Concern::Dereferenceable
|
86
85
|
include Concern::Observable
|
87
86
|
include Concern::Logging
|
88
|
-
include Concern::Deprecation
|
89
87
|
|
90
88
|
attr_reader :timeout, :io_executor, :fast_executor
|
91
89
|
|
@@ -95,15 +93,8 @@ module Concurrent
|
|
95
93
|
#
|
96
94
|
# @!macro executor_and_deref_options
|
97
95
|
def initialize(initial, opts = {})
|
98
|
-
|
99
|
-
|
100
|
-
@validator = Proc.new { |result| true }
|
101
|
-
self.observers = Collection::CopyOnWriteObserverSet.new
|
102
|
-
@serialized_execution = SerializedExecution.new
|
103
|
-
@io_executor = Executor.executor_from_options(opts) || Concurrent.global_io_executor
|
104
|
-
@fast_executor = Executor.executor_from_options(opts) || Concurrent.global_fast_executor
|
105
|
-
init_mutex
|
106
|
-
set_deref_options(opts)
|
96
|
+
super()
|
97
|
+
synchronize { ns_initialize(initial, opts) }
|
107
98
|
end
|
108
99
|
|
109
100
|
# Specifies a block fast to be performed when an update fast raises
|
@@ -129,9 +120,7 @@ module Concurrent
|
|
129
120
|
# #=> puts "Pow!"
|
130
121
|
def rescue(clazz = StandardError, &block)
|
131
122
|
unless block.nil?
|
132
|
-
|
133
|
-
@rescuers << Rescuer.new(clazz, block)
|
134
|
-
end
|
123
|
+
synchronize { @rescuers << Rescuer.new(clazz, block) }
|
135
124
|
end
|
136
125
|
self
|
137
126
|
end
|
@@ -139,7 +128,7 @@ module Concurrent
|
|
139
128
|
alias_method :catch, :rescue
|
140
129
|
alias_method :on_error, :rescue
|
141
130
|
|
142
|
-
# A block
|
131
|
+
# A block task to be performed after every update to validate if the new
|
143
132
|
# value is valid. If the new value is not valid then the current value is not
|
144
133
|
# updated. If no validator is provided then all updates are considered valid.
|
145
134
|
#
|
@@ -150,12 +139,7 @@ module Concurrent
|
|
150
139
|
def validate(&block)
|
151
140
|
|
152
141
|
unless block.nil?
|
153
|
-
|
154
|
-
mutex.lock
|
155
|
-
@validator = block
|
156
|
-
ensure
|
157
|
-
mutex.unlock
|
158
|
-
end
|
142
|
+
synchronize { @validator = block }
|
159
143
|
end
|
160
144
|
self
|
161
145
|
end
|
@@ -179,30 +163,13 @@ module Concurrent
|
|
179
163
|
# Update the current value with the result of the given block fast,
|
180
164
|
# block can do blocking calls
|
181
165
|
#
|
182
|
-
# @param [Fixnum, nil] timeout [DEPRECATED] maximum number of seconds before an update is cancelled
|
183
|
-
#
|
184
166
|
# @yield the fast to be performed with the current value in order to calculate
|
185
167
|
# the new value
|
186
168
|
# @yieldparam [Object] value the current value
|
187
169
|
# @yieldreturn [Object] the new value
|
188
170
|
# @return [true, nil] nil when no block is given
|
189
|
-
def post_off(
|
190
|
-
|
191
|
-
deprecated 'post_off with option timeout options is deprecated and will be removed'
|
192
|
-
lambda do |value|
|
193
|
-
future = Future.execute do
|
194
|
-
block.call(value)
|
195
|
-
end
|
196
|
-
if future.wait(timeout)
|
197
|
-
future.value!
|
198
|
-
else
|
199
|
-
raise Concurrent::TimeoutError
|
200
|
-
end
|
201
|
-
end
|
202
|
-
else
|
203
|
-
block
|
204
|
-
end
|
205
|
-
post_on(@io_executor, &task)
|
171
|
+
def post_off(&block)
|
172
|
+
post_on(@io_executor, &block)
|
206
173
|
end
|
207
174
|
|
208
175
|
# Update the current value with the result of the given block fast,
|
@@ -227,6 +194,20 @@ module Concurrent
|
|
227
194
|
done.wait timeout
|
228
195
|
end
|
229
196
|
|
197
|
+
protected
|
198
|
+
|
199
|
+
def ns_initialize(initial, opts)
|
200
|
+
init_mutex(self)
|
201
|
+
@value = initial
|
202
|
+
@rescuers = []
|
203
|
+
@validator = Proc.new { |result| true }
|
204
|
+
self.observers = Collection::CopyOnWriteObserverSet.new
|
205
|
+
@serialized_execution = SerializedExecution.new
|
206
|
+
@io_executor = Executor.executor_from_options(opts) || Concurrent.global_io_executor
|
207
|
+
@fast_executor = Executor.executor_from_options(opts) || Concurrent.global_fast_executor
|
208
|
+
set_deref_options(opts)
|
209
|
+
end
|
210
|
+
|
230
211
|
private
|
231
212
|
|
232
213
|
def post_on(executor, &block)
|
@@ -240,7 +221,7 @@ module Concurrent
|
|
240
221
|
|
241
222
|
# @!visibility private
|
242
223
|
def try_rescue(ex) # :nodoc:
|
243
|
-
rescuer =
|
224
|
+
rescuer = synchronize do
|
244
225
|
@rescuers.find { |r| ex.is_a?(r.clazz) }
|
245
226
|
end
|
246
227
|
rescuer.block.call(ex) if rescuer
|
@@ -251,7 +232,7 @@ module Concurrent
|
|
251
232
|
|
252
233
|
# @!visibility private
|
253
234
|
def work(&handler) # :nodoc:
|
254
|
-
validator, value =
|
235
|
+
validator, value = synchronize { [@validator, @value] }
|
255
236
|
|
256
237
|
begin
|
257
238
|
result = handler.call(value)
|
@@ -260,14 +241,11 @@ module Concurrent
|
|
260
241
|
exception = ex
|
261
242
|
end
|
262
243
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
end
|
269
|
-
ensure
|
270
|
-
mutex.unlock
|
244
|
+
should_notify = synchronize do
|
245
|
+
if !exception && valid
|
246
|
+
@value = result
|
247
|
+
true
|
248
|
+
end
|
271
249
|
end
|
272
250
|
|
273
251
|
if should_notify
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'concurrent/synchronization'
|
1
2
|
require 'concurrent/channel/waitable_list'
|
2
3
|
|
3
4
|
module Concurrent
|
@@ -5,14 +6,11 @@ module Concurrent
|
|
5
6
|
|
6
7
|
# @api Channel
|
7
8
|
# @!macro edge_warning
|
8
|
-
class BufferedChannel
|
9
|
+
class BufferedChannel < Synchronization::Object
|
9
10
|
|
10
11
|
def initialize(size)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
@probe_set = WaitableList.new
|
15
|
-
@buffer = RingBuffer.new(size)
|
12
|
+
super()
|
13
|
+
synchronize { ns_initialize(size) }
|
16
14
|
end
|
17
15
|
|
18
16
|
def probe_set_size
|
@@ -20,11 +18,11 @@ module Concurrent
|
|
20
18
|
end
|
21
19
|
|
22
20
|
def buffer_queue_size
|
23
|
-
|
21
|
+
synchronize { @buffer.count }
|
24
22
|
end
|
25
23
|
|
26
24
|
def push(value)
|
27
|
-
until
|
25
|
+
until set_probe_or_ns_push_into_buffer(value)
|
28
26
|
end
|
29
27
|
end
|
30
28
|
|
@@ -35,15 +33,13 @@ module Concurrent
|
|
35
33
|
end
|
36
34
|
|
37
35
|
def select(probe)
|
38
|
-
|
39
|
-
|
36
|
+
synchronize do
|
40
37
|
if @buffer.empty?
|
41
38
|
@probe_set.put(probe)
|
42
39
|
true
|
43
40
|
else
|
44
|
-
|
41
|
+
ns_shift_buffer if probe.try_set([ns_peek_buffer, self])
|
45
42
|
end
|
46
|
-
|
47
43
|
end
|
48
44
|
end
|
49
45
|
|
@@ -51,37 +47,43 @@ module Concurrent
|
|
51
47
|
@probe_set.delete(probe)
|
52
48
|
end
|
53
49
|
|
50
|
+
protected
|
51
|
+
|
52
|
+
def ns_initialize(size)
|
53
|
+
@probe_set = WaitableList.new
|
54
|
+
@buffer = RingBuffer.new(size)
|
55
|
+
end
|
56
|
+
|
54
57
|
private
|
55
58
|
|
56
|
-
def
|
57
|
-
|
59
|
+
def ns_push_into_buffer(value)
|
60
|
+
ns_wait while @buffer.full?
|
58
61
|
@buffer.offer value
|
59
|
-
|
62
|
+
ns_broadcast
|
60
63
|
end
|
61
64
|
|
62
|
-
def
|
63
|
-
|
65
|
+
def ns_peek_buffer
|
66
|
+
ns_wait while @buffer.empty?
|
64
67
|
@buffer.peek
|
65
68
|
end
|
66
69
|
|
67
|
-
def
|
68
|
-
|
70
|
+
def ns_shift_buffer
|
71
|
+
ns_wait while @buffer.empty?
|
69
72
|
result = @buffer.poll
|
70
|
-
|
73
|
+
ns_broadcast
|
71
74
|
result
|
72
75
|
end
|
73
76
|
|
74
|
-
def
|
75
|
-
|
77
|
+
def set_probe_or_ns_push_into_buffer(value)
|
78
|
+
synchronize do
|
76
79
|
if @probe_set.empty?
|
77
|
-
|
80
|
+
ns_push_into_buffer(value)
|
78
81
|
true
|
79
82
|
else
|
80
83
|
@probe_set.take.try_set([value, self])
|
81
84
|
end
|
82
85
|
end
|
83
86
|
end
|
84
|
-
|
85
87
|
end
|
86
88
|
end
|
87
89
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'concurrent' # TODO do not require whole concurrent gem
|
2
|
+
require 'concurrent/concern/deprecation'
|
2
3
|
require 'concurrent/edge/lock_free_stack'
|
3
4
|
|
4
5
|
|
@@ -602,7 +603,7 @@ module Concurrent
|
|
602
603
|
def exception(*args)
|
603
604
|
raise 'obligation is not failed' unless failed?
|
604
605
|
reason = @State.get.reason
|
605
|
-
if reason.is_a?(Array)
|
606
|
+
if reason.is_a?(::Array)
|
606
607
|
reason.each { |e| log ERROR, 'Edge::Future', e }
|
607
608
|
Concurrent::Error.new 'multiple exceptions, inspect log'
|
608
609
|
else
|
@@ -1014,7 +1015,7 @@ module Concurrent
|
|
1014
1015
|
private
|
1015
1016
|
|
1016
1017
|
def initialize_blocked_by(blocked_by_futures)
|
1017
|
-
@BlockedBy =
|
1018
|
+
@BlockedBy = [blocked_by_futures].flatten
|
1018
1019
|
end
|
1019
1020
|
|
1020
1021
|
def clear_blocked_by!
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: concurrent-ruby-edge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0.pre1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jerry D'Antonio
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2015-
|
13
|
+
date: 2015-08-19 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: concurrent-ruby
|
@@ -18,14 +18,14 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - "~>"
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.
|
21
|
+
version: 1.0.0.pre1
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: 0.
|
28
|
+
version: 1.0.0.pre1
|
29
29
|
description: |
|
30
30
|
These features are under active development and may change frequently. They are expected not to
|
31
31
|
keep backward compatibility (there may also lack tests and documentation). Semantic versions will
|
@@ -100,9 +100,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
100
100
|
version: 1.9.3
|
101
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
102
|
requirements:
|
103
|
-
- - "
|
103
|
+
- - ">"
|
104
104
|
- !ruby/object:Gem::Version
|
105
|
-
version:
|
105
|
+
version: 1.3.1
|
106
106
|
requirements: []
|
107
107
|
rubyforge_project:
|
108
108
|
rubygems_version: 2.4.8
|