concurrent-ruby-edge 0.1.2 → 0.2.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|