concurrent-ruby-edge 0.1.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +284 -0
- data/lib/concurrent-edge.rb +11 -0
- data/lib/concurrent/actor.rb +98 -0
- data/lib/concurrent/actor/behaviour.rb +143 -0
- data/lib/concurrent/actor/behaviour/abstract.rb +51 -0
- data/lib/concurrent/actor/behaviour/awaits.rb +21 -0
- data/lib/concurrent/actor/behaviour/buffer.rb +56 -0
- data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +12 -0
- data/lib/concurrent/actor/behaviour/executes_context.rb +17 -0
- data/lib/concurrent/actor/behaviour/linking.rb +83 -0
- data/lib/concurrent/actor/behaviour/pausing.rb +123 -0
- data/lib/concurrent/actor/behaviour/removes_child.rb +16 -0
- data/lib/concurrent/actor/behaviour/sets_results.rb +37 -0
- data/lib/concurrent/actor/behaviour/supervising.rb +39 -0
- data/lib/concurrent/actor/behaviour/terminates_children.rb +14 -0
- data/lib/concurrent/actor/behaviour/termination.rb +74 -0
- data/lib/concurrent/actor/context.rb +167 -0
- data/lib/concurrent/actor/core.rb +220 -0
- data/lib/concurrent/actor/default_dead_letter_handler.rb +9 -0
- data/lib/concurrent/actor/envelope.rb +41 -0
- data/lib/concurrent/actor/errors.rb +27 -0
- data/lib/concurrent/actor/internal_delegations.rb +59 -0
- data/lib/concurrent/actor/public_delegations.rb +40 -0
- data/lib/concurrent/actor/reference.rb +106 -0
- data/lib/concurrent/actor/root.rb +37 -0
- data/lib/concurrent/actor/type_check.rb +48 -0
- data/lib/concurrent/actor/utils.rb +10 -0
- data/lib/concurrent/actor/utils/ad_hoc.rb +27 -0
- data/lib/concurrent/actor/utils/balancer.rb +43 -0
- data/lib/concurrent/actor/utils/broadcast.rb +52 -0
- data/lib/concurrent/actor/utils/pool.rb +54 -0
- data/lib/concurrent/agent.rb +289 -0
- data/lib/concurrent/channel.rb +6 -0
- data/lib/concurrent/channel/blocking_ring_buffer.rb +82 -0
- data/lib/concurrent/channel/buffered_channel.rb +87 -0
- data/lib/concurrent/channel/channel.rb +19 -0
- data/lib/concurrent/channel/ring_buffer.rb +65 -0
- data/lib/concurrent/channel/unbuffered_channel.rb +39 -0
- data/lib/concurrent/channel/waitable_list.rb +48 -0
- data/lib/concurrent/edge/atomic_markable_reference.rb +184 -0
- data/lib/concurrent/edge/future.rb +1226 -0
- data/lib/concurrent/edge/lock_free_stack.rb +85 -0
- metadata +110 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 21429b1dcafe35b79201be08fd02442171fc68fb
|
4
|
+
data.tar.gz: 2de92c445f74fbf670cb605e760b9a4c413597c4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cb45d38d9f966ff005121fec47adc053349675ee7d018662e7b49c67a67fdd3c3bb603cca559d3b39c4243f62ff099905c72b320b2ada6b29d8d5fc00541df49
|
7
|
+
data.tar.gz: 2e1c9c51ec89bb08e32ced3883cf5fa8cf472bdf0a98616af1966e7929c2c018ee832b747262fff13831295aa381c67cf883f207f60c9dfa29355c504803563d
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) Jerry D'Antonio -- released under the MIT license.
|
2
|
+
|
3
|
+
http://www.opensource.org/licenses/mit-license.php
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,284 @@
|
|
1
|
+
# Concurrent Ruby
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/concurrent-ruby.svg)](http://badge.fury.io/rb/concurrent-ruby) [![Build Status](https://travis-ci.org/ruby-concurrency/concurrent-ruby.svg?branch=master)](https://travis-ci.org/ruby-concurrency/concurrent-ruby) [![Code Climate](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby.svg)](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby) [![Inline docs](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby.svg)](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby) [![Dependency Status](https://gemnasium.com/ruby-concurrency/concurrent-ruby.svg)](https://gemnasium.com/ruby-concurrency/concurrent-ruby) [![License](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT) [![Gitter chat](http://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/ruby-concurrency/concurrent-ruby)
|
3
|
+
|
4
|
+
<table>
|
5
|
+
<tr>
|
6
|
+
<td align="left" valign="top">
|
7
|
+
<p>
|
8
|
+
Modern concurrency tools for Ruby. Inspired by
|
9
|
+
<a href="http://www.erlang.org/doc/reference_manual/processes.html">Erlang</a>,
|
10
|
+
<a href="http://clojure.org/concurrent_programming">Clojure</a>,
|
11
|
+
<a href="http://akka.io/">Scala</a>,
|
12
|
+
<a href="http://www.haskell.org/haskellwiki/Applications_and_libraries/Concurrency_and_parallelism#Concurrent_Haskell">Haskell</a>,
|
13
|
+
<a href="http://blogs.msdn.com/b/dsyme/archive/2010/02/15/async-and-parallel-design-patterns-in-f-part-3-agents.aspx">F#</a>,
|
14
|
+
<a href="http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx">C#</a>,
|
15
|
+
<a href="http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html">Java</a>,
|
16
|
+
and classic concurrency patterns.
|
17
|
+
</p>
|
18
|
+
<p>
|
19
|
+
The design goals of this gem are:
|
20
|
+
<ul>
|
21
|
+
<li>Be an 'unopinionated' toolbox that provides useful utilities without debating which is better or why</li>
|
22
|
+
<li>Remain free of external gem dependencies</li>
|
23
|
+
<li>Stay true to the spirit of the languages providing inspiration</li>
|
24
|
+
<li>But implement in a way that makes sense for Ruby</li>
|
25
|
+
<li>Keep the semantics as idiomatic Ruby as possible</li>
|
26
|
+
<li>Support features that make sense in Ruby</li>
|
27
|
+
<li>Exclude features that don't make sense in Ruby</li>
|
28
|
+
<li>Be small, lean, and loosely coupled</li>
|
29
|
+
</ul>
|
30
|
+
</p>
|
31
|
+
</td>
|
32
|
+
<td align="right" valign="top">
|
33
|
+
<img src="https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/logo/concurrent-ruby-logo-300x300.png"/>
|
34
|
+
</td>
|
35
|
+
</tr>
|
36
|
+
</table>
|
37
|
+
|
38
|
+
### Supported Ruby versions
|
39
|
+
|
40
|
+
MRI 1.9.3, 2.0, 2.1, 2.2, JRuby (1.9 mode), and Rubinius 2.x are supported.
|
41
|
+
This gem should be fully compatible with any interpreter that is compliant with Ruby 1.9.3 or newer.
|
42
|
+
|
43
|
+
## Features & Documentation
|
44
|
+
|
45
|
+
We have a roadmap guiding our work toward the [v1.0.0 release](https://github.com/ruby-concurrency/concurrent-ruby/wiki/v1.0-Roadmap).
|
46
|
+
|
47
|
+
The primary site for documentation is the automatically generated [API documentation](http://ruby-concurrency.github.io/concurrent-ruby/frames.html)
|
48
|
+
|
49
|
+
We also have a [mailing list](http://groups.google.com/group/concurrent-ruby).
|
50
|
+
|
51
|
+
This library contains a variety of concurrency abstractions at high and low levels. One of the high-level abstractions is likely to meet most common needs.
|
52
|
+
|
53
|
+
#### General-purpose Concurrency Abstractions
|
54
|
+
|
55
|
+
* [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.
|
56
|
+
* [Atom](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Atom.html): A way to manage shared, synchronous, independent state.
|
57
|
+
* [Future](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Future.html): An asynchronous operation that produces a value.
|
58
|
+
* [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.
|
59
|
+
* [Promise](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promise.html): Similar to Futures, with more features.
|
60
|
+
* [ScheduledTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ScheduledTask.html): Like a Future scheduled for a specific future time.
|
61
|
+
* [TimerTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TimerTask.html): A Thread that periodically wakes up to perform work at regular intervals.
|
62
|
+
|
63
|
+
#### Thread-safe Value Objects
|
64
|
+
|
65
|
+
* `Maybe` A thread-safe, immutable object representing an optional value, based on
|
66
|
+
[Haskell Data.Maybe](https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-Maybe.html).
|
67
|
+
* `Delay` Lazy evaluation of a block yielding an immutable result. Based on Clojure's
|
68
|
+
[delay](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Delay.html).
|
69
|
+
|
70
|
+
#### Thread-safe Structures
|
71
|
+
|
72
|
+
Derived from Ruby's [Struct](http://ruby-doc.org/core-2.2.0/Struct.html):
|
73
|
+
|
74
|
+
* `ImmutableStruct` Immutable struct where values are set at construction and cannot be changed later.
|
75
|
+
* `MutableStruct` Synchronized, mutable struct where values can be safely changed at any time.
|
76
|
+
* `SettableStruct` Synchronized, write-once struct where values can be set at most once, either at construction or any time thereafter.
|
77
|
+
|
78
|
+
#### Java-inspired ThreadPools and Other Executors
|
79
|
+
|
80
|
+
* See [ThreadPool](http://ruby-concurrency.github.io/concurrent-ruby/file.thread_pools.html) overview, which also contains a list of other Executors available.
|
81
|
+
|
82
|
+
#### Thread Synchronization Classes and Algorithms
|
83
|
+
|
84
|
+
* [CountdownLatch](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CountDownLatch.html)
|
85
|
+
* [CyclicBarrier](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CyclicBarrier.html)
|
86
|
+
* [Event](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Event.html)
|
87
|
+
* [Semaphore](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Semaphore.html)
|
88
|
+
|
89
|
+
#### Thread-safe Variables
|
90
|
+
|
91
|
+
* [AtomicBoolean](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/AtomicBoolean.html)
|
92
|
+
* [AtomicFixnum](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/AtomicFixnum.html)
|
93
|
+
* [AtomicReference](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MutexAtomic.html)
|
94
|
+
* [I-Structures](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/IVar.html) (IVar)
|
95
|
+
* [M-Structures](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MVar.html) (MVar)
|
96
|
+
* [Thread-local variables](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ThreadLocalVar.html)
|
97
|
+
* [Software transactional memory](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TVar.html) (TVar)
|
98
|
+
* [ReadWriteLock](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ReadWriteLock.html)
|
99
|
+
|
100
|
+
### Edge Features
|
101
|
+
|
102
|
+
These are available in the `concurrent-ruby-edge` companion gem, installed with `gem install concurrent-ruby-edge`.
|
103
|
+
|
104
|
+
These features are under active development and may change frequently. They are expected not to
|
105
|
+
keep backward compatibility (there may also lack tests and documentation). Semantic versions will
|
106
|
+
be obeyed though. Features developed in `concurrent-ruby-edge` are expected to move to `concurrent-ruby` when final.
|
107
|
+
|
108
|
+
* [Actor](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Actor.html):
|
109
|
+
Implements the Actor Model, where concurrent actors exchange messages.
|
110
|
+
* [new Future Framework](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Edge.html) - new
|
111
|
+
unified implementation of Futures and Promises which combines Features of previous `Future`,
|
112
|
+
`Promise`, `IVar`, `Event`, `Probe`, `dataflow`, `Delay`, `TimerTask` into single framework. It uses extensively
|
113
|
+
new synchronization layer to make all the paths **lock-free** with exception of blocking threads on `#wait`.
|
114
|
+
It offers better performance and does not block threads when not required.
|
115
|
+
* [Agent](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Agent.html): A single atomic value that represents an identity.
|
116
|
+
* [Channel](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Channel.html):
|
117
|
+
Communicating Sequential Processes (CSP).
|
118
|
+
* [Exchanger](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Exchanger.html)
|
119
|
+
* [LazyRegister](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/LazyRegister.html)
|
120
|
+
* [New Future Promise Framework](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Edge.html) - new
|
121
|
+
unified implementation of Futures and Promises which combines Features of previous `Future`,
|
122
|
+
`Promise`, `IVar`, `Probe`, `dataflow`, `Delay`, `TimerTask` into single framework. It uses extensively
|
123
|
+
new synchronization layer to make all the paths lock-free with exception of blocking threads on `#wait`.
|
124
|
+
It offers better performance and does not block threads (exception being `#wait` and similar methods where it's
|
125
|
+
intended).
|
126
|
+
|
127
|
+
|
128
|
+
#### Statuses:
|
129
|
+
|
130
|
+
*Why is not in core?*
|
131
|
+
|
132
|
+
- **Actor** - partial documentation and tests, stability good.
|
133
|
+
- **Future/Promise Framework** - partial documentation and tests, stability good.
|
134
|
+
- **Agent** - incomplete behaviour compared to Clojure's model, stability good.
|
135
|
+
- **Channel** - missing documentation, stability good.
|
136
|
+
- **Exchanger** - known race issue.
|
137
|
+
- **LazyRegister** - missing documentation and tests.
|
138
|
+
|
139
|
+
## Usage
|
140
|
+
|
141
|
+
All abstractions within this gem can be loaded simply by requiring it:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
require 'concurrent'
|
145
|
+
```
|
146
|
+
|
147
|
+
To reduce the amount of code loaded at runtime, subsets of this gem can be required:
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
require 'concurrent' # everything
|
151
|
+
|
152
|
+
# groups
|
153
|
+
|
154
|
+
require 'concurrent/atomics' # atomic and thread synchronization classes
|
155
|
+
require 'concurrent/executors' # Thread pools and other executors
|
156
|
+
|
157
|
+
# individual abstractions
|
158
|
+
|
159
|
+
require 'concurrent/async' # Concurrent::Async
|
160
|
+
require 'concurrent/atom' # Concurrent::Atom
|
161
|
+
require 'concurrent/dataflow' # Concurrent::dataflow
|
162
|
+
require 'concurrent/delay' # Concurrent::Delay
|
163
|
+
require 'concurrent/future' # Concurrent::Future
|
164
|
+
require 'concurrent/immutable_struct' # Concurrent::ImmutableStruct
|
165
|
+
require 'concurrent/ivar' # Concurrent::IVar
|
166
|
+
require 'concurrent/maybe' # Concurrent::Maybe
|
167
|
+
require 'concurrent/mutable_struct' # Concurrent::MutableStruct
|
168
|
+
require 'concurrent/mvar' # Concurrent::MVar
|
169
|
+
require 'concurrent/promise' # Concurrent::Promise
|
170
|
+
require 'concurrent/scheduled_task' # Concurrent::ScheduledTask
|
171
|
+
require 'concurrent/settable_struct' # Concurrent::SettableStruct
|
172
|
+
require 'concurrent/timer_task' # Concurrent::TimerTask
|
173
|
+
require 'concurrent/tvar' # Concurrent::TVar
|
174
|
+
|
175
|
+
# experimental - available in `concurrent-ruby-edge` companion gem
|
176
|
+
|
177
|
+
require 'concurrent/actor' # Concurrent::Actor and supporting code
|
178
|
+
require 'concurrent/edge/future' # new Future Framework
|
179
|
+
require 'concurrent/agent' # Concurrent::Agent
|
180
|
+
require 'concurrent/channel ' # Concurrent::Channel and supporting code
|
181
|
+
require 'concurrent/exchanger' # Concurrent::Exchanger
|
182
|
+
require 'concurrent/lazy_register' # Concurrent::LazyRegister
|
183
|
+
```
|
184
|
+
|
185
|
+
If the library does not behave as expected, `Concurrent.use_stdlib_logger(Logger::DEBUG)` could help to reveal the problem.
|
186
|
+
|
187
|
+
## Installation
|
188
|
+
|
189
|
+
```shell
|
190
|
+
gem install concurrent-ruby
|
191
|
+
```
|
192
|
+
|
193
|
+
or add the following line to Gemfile:
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
gem 'concurrent-ruby'
|
197
|
+
```
|
198
|
+
|
199
|
+
and run `bundle install` from your shell.
|
200
|
+
|
201
|
+
### C Extensions for MRI
|
202
|
+
|
203
|
+
Potential performance improvements may be achieved under MRI by installing optional C extensions.
|
204
|
+
To minimize installation errors the C extensions are available in the `concurrent-ruby-ext` extension
|
205
|
+
gem. `concurrent-ruby` and `concurrent-ruby-ext` are always released together with same version.
|
206
|
+
Simply install the extension gem too:
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
gem install concurrent-ruby-ext
|
210
|
+
```
|
211
|
+
|
212
|
+
or add the following line to Gemfile:
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
gem 'concurrent-ruby-ext'
|
216
|
+
```
|
217
|
+
|
218
|
+
and run `bundle install` from your shell.
|
219
|
+
|
220
|
+
In code it is only necessary to
|
221
|
+
|
222
|
+
```ruby
|
223
|
+
require 'concurrent'
|
224
|
+
```
|
225
|
+
|
226
|
+
The `concurrent-ruby` gem will automatically detect the presence of the `concurrent-ruby-ext` gem
|
227
|
+
and load the appropriate C extensions.
|
228
|
+
|
229
|
+
#### Note For gem developers
|
230
|
+
|
231
|
+
No gems should depend on `concurrent-ruby-ext`. Doing so will force C extensions on your users.
|
232
|
+
The best practice is to depend on `concurrent-ruby` and let users to decide if they want C extensions.
|
233
|
+
|
234
|
+
### Building
|
235
|
+
|
236
|
+
All published versions of this gem (core, extension, and several platform-specific packages) are compiled,
|
237
|
+
packaged, tested, and published using an open, [automated process](https://github.com/ruby-concurrency/rake-compiler-dev-box).
|
238
|
+
This process can also be used to create pre-compiled binaries of the extension gem for virtally
|
239
|
+
any platform. *Documentation is forthcoming...*
|
240
|
+
|
241
|
+
```
|
242
|
+
*MRI only*
|
243
|
+
bundle exec rake build:native # Build concurrent-ruby-ext-<version>-<platform>.gem into the pkg dir
|
244
|
+
bundle exec rake compile:extension # Compile extension
|
245
|
+
|
246
|
+
*JRuby only*
|
247
|
+
bundle exec rake build # Build JRuby-specific core gem (alias for `build:core`)
|
248
|
+
bundle exec rake build:core # Build concurrent-ruby-<version>-java.gem into the pkg directory
|
249
|
+
|
250
|
+
*All except JRuby*
|
251
|
+
bundle exec rake build # Build core and extension gems
|
252
|
+
bundle exec rake build:core # Build concurrent-ruby-<version>.gem into the pkg directory
|
253
|
+
bundle exec rake build:ext # Build concurrent-ruby-ext-<version>.gem into the pkg directory
|
254
|
+
|
255
|
+
*All*
|
256
|
+
bundle exec rake clean # Remove any temporary products
|
257
|
+
bundle exec rake clobber # Remove any generated file
|
258
|
+
bundle exec rake compile # Compile all the extensions
|
259
|
+
```
|
260
|
+
|
261
|
+
## Maintainers
|
262
|
+
|
263
|
+
* [Jerry D'Antonio](https://github.com/jdantonio)
|
264
|
+
* [Michele Della Torre](https://github.com/mighe)
|
265
|
+
* [Chris Seaton](https://github.com/chrisseaton)
|
266
|
+
* [Lucas Allan](https://github.com/lucasallan)
|
267
|
+
* [Petr Chalupa](https://github.com/pitr-ch)
|
268
|
+
* [Paweł Obrok](https://github.com/obrok)
|
269
|
+
|
270
|
+
## Contributing
|
271
|
+
|
272
|
+
1. Fork it
|
273
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
274
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
275
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
276
|
+
5. Create new Pull Request
|
277
|
+
|
278
|
+
## License and Copyright
|
279
|
+
|
280
|
+
*Concurrent Ruby* is free software released under the [MIT License](http://www.opensource.org/licenses/MIT).
|
281
|
+
|
282
|
+
The *Concurrent Ruby* [logo](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Logo)
|
283
|
+
was designed by [David Jones](https://twitter.com/zombyboy).
|
284
|
+
It is Copyright © 2014 [Jerry D'Antonio](https://twitter.com/jerrydantonio). All Rights Reserved.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'concurrent'
|
2
|
+
|
3
|
+
require 'concurrent/actor'
|
4
|
+
require 'concurrent/agent'
|
5
|
+
require 'concurrent/channel'
|
6
|
+
require 'concurrent/exchanger'
|
7
|
+
require 'concurrent/lazy_register'
|
8
|
+
|
9
|
+
require 'concurrent/edge/future'
|
10
|
+
require 'concurrent/edge/lock_free_stack'
|
11
|
+
require 'concurrent/edge/atomic_markable_reference'
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'concurrent/configuration'
|
2
|
+
require 'concurrent/executor/serialized_execution'
|
3
|
+
require 'concurrent/synchronization'
|
4
|
+
require 'concurrent/edge/future'
|
5
|
+
|
6
|
+
module Concurrent
|
7
|
+
# TODO https://github.com/celluloid/celluloid/wiki/Supervision-Groups ?
|
8
|
+
# TODO Remote actors using DRb
|
9
|
+
# TODO un/become
|
10
|
+
# TODO supervision tree, pause children on error in parent, pause may need higher priority
|
11
|
+
# TODO more effective executor
|
12
|
+
|
13
|
+
# {include:file:doc/actor/main.md}
|
14
|
+
# @api Actor
|
15
|
+
# @!macro edge_warning
|
16
|
+
module Actor
|
17
|
+
|
18
|
+
require 'concurrent/actor/type_check'
|
19
|
+
require 'concurrent/actor/errors'
|
20
|
+
require 'concurrent/actor/public_delegations'
|
21
|
+
require 'concurrent/actor/internal_delegations'
|
22
|
+
require 'concurrent/actor/envelope'
|
23
|
+
require 'concurrent/actor/reference'
|
24
|
+
require 'concurrent/actor/core'
|
25
|
+
require 'concurrent/actor/behaviour'
|
26
|
+
require 'concurrent/actor/context'
|
27
|
+
|
28
|
+
require 'concurrent/actor/default_dead_letter_handler'
|
29
|
+
require 'concurrent/actor/root'
|
30
|
+
require 'concurrent/actor/utils'
|
31
|
+
|
32
|
+
# @return [Reference, nil] current executing actor if any
|
33
|
+
def self.current
|
34
|
+
Thread.current[:__current_actor__]
|
35
|
+
end
|
36
|
+
|
37
|
+
@root = Concurrent.delay do
|
38
|
+
Core.new(parent: nil, name: '/', class: Root, initialized: future = Concurrent.future).reference.tap do
|
39
|
+
future.wait!
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# A root actor, a default parent of all actors spawned outside an actor
|
44
|
+
def self.root
|
45
|
+
@root.value!
|
46
|
+
end
|
47
|
+
|
48
|
+
# Spawns a new actor. {Concurrent::Actor::AbstractContext.spawn} allows to omit class parameter.
|
49
|
+
# To see the list of avaliable options see {Core#initialize}
|
50
|
+
# @see Concurrent::Actor::AbstractContext.spawn
|
51
|
+
# @see Core#initialize
|
52
|
+
# @example by class and name
|
53
|
+
# Actor.spawn(AdHoc, :ping1) { -> message { message } }
|
54
|
+
#
|
55
|
+
# @example by option hash
|
56
|
+
# inc2 = Actor.spawn(class: AdHoc,
|
57
|
+
# name: 'increment by 2',
|
58
|
+
# args: [2],
|
59
|
+
# executor: Concurrent.global_io_executor) do |increment_by|
|
60
|
+
# lambda { |number| number + increment_by }
|
61
|
+
# end
|
62
|
+
# inc2.ask!(2) # => 4
|
63
|
+
#
|
64
|
+
# @param block for context_class instantiation
|
65
|
+
# @param args see {.to_spawn_options}
|
66
|
+
# @return [Reference] never the actual actor
|
67
|
+
def self.spawn(*args, &block)
|
68
|
+
if Actor.current
|
69
|
+
Core.new(to_spawn_options(*args).merge(parent: Actor.current), &block).reference
|
70
|
+
else
|
71
|
+
root.ask([:spawn, to_spawn_options(*args), block]).value!
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# as {.spawn} but it'll block until actor is initialized or it'll raise exception on error
|
76
|
+
def self.spawn!(*args, &block)
|
77
|
+
spawn(to_spawn_options(*args).merge(initialized: future = Concurrent.future), &block).tap { future.wait! }
|
78
|
+
end
|
79
|
+
|
80
|
+
# @overload to_spawn_options(context_class, name, *args)
|
81
|
+
# @param [AbstractContext] context_class to be spawned
|
82
|
+
# @param [String, Symbol] name of the instance, it's used to generate the
|
83
|
+
# {Core#path} of the actor
|
84
|
+
# @param args for context_class instantiation
|
85
|
+
# @overload to_spawn_options(opts)
|
86
|
+
# see {Core#initialize} opts
|
87
|
+
def self.to_spawn_options(*args)
|
88
|
+
if args.size == 1 && args.first.is_a?(Hash)
|
89
|
+
args.first
|
90
|
+
else
|
91
|
+
{ class: args[0],
|
92
|
+
name: args[1],
|
93
|
+
args: args[2..-1] }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module Concurrent
|
2
|
+
module Actor
|
3
|
+
|
4
|
+
# Actors have modular architecture, which is achieved by combining a light core with chain of
|
5
|
+
# behaviours. Each message or internal event propagates through the chain allowing the
|
6
|
+
# behaviours react based on their responsibility.
|
7
|
+
#
|
8
|
+
# - {Behaviour::Linking}:
|
9
|
+
#
|
10
|
+
# > {include:Actor::Behaviour::Linking}
|
11
|
+
#
|
12
|
+
# - {Behaviour::Awaits}:
|
13
|
+
#
|
14
|
+
# > {include:Actor::Behaviour::Awaits}
|
15
|
+
#
|
16
|
+
# - {Behaviour::Pausing}:
|
17
|
+
#
|
18
|
+
# > {include:Actor::Behaviour::Pausing}
|
19
|
+
#
|
20
|
+
# - {Behaviour::Supervising}:
|
21
|
+
#
|
22
|
+
# > {include:Actor::Behaviour::Supervising}
|
23
|
+
#
|
24
|
+
# - {Behaviour::Supervising}:
|
25
|
+
#
|
26
|
+
# > {include:Actor::Behaviour::Supervising}
|
27
|
+
#
|
28
|
+
# - {Behaviour::ExecutesContext}:
|
29
|
+
#
|
30
|
+
# > {include:Actor::Behaviour::ExecutesContext}
|
31
|
+
#
|
32
|
+
# - {Behaviour::ErrorsOnUnknownMessage}:
|
33
|
+
#
|
34
|
+
# > {include:Actor::Behaviour::ErrorsOnUnknownMessage}
|
35
|
+
#
|
36
|
+
# - {Behaviour::Termination}:
|
37
|
+
#
|
38
|
+
# > {include:Actor::Behaviour::Termination}
|
39
|
+
#
|
40
|
+
# - {Behaviour::TerminatesChildren}:
|
41
|
+
#
|
42
|
+
# > {include:Actor::Behaviour::TerminatesChildren}
|
43
|
+
#
|
44
|
+
# - {Behaviour::RemovesChild}:
|
45
|
+
#
|
46
|
+
# > {include:Actor::Behaviour::RemovesChild}
|
47
|
+
#
|
48
|
+
# If needed new behaviours can be added, or old one removed to get required behaviour.
|
49
|
+
#
|
50
|
+
# - {Context} uses
|
51
|
+
# {include:Actor::Behaviour.basic_behaviour_definition}
|
52
|
+
#
|
53
|
+
# - {RestartingContext} uses
|
54
|
+
# {include:Actor::Behaviour.restarting_behaviour_definition}
|
55
|
+
module Behaviour
|
56
|
+
MESSAGE_PROCESSED = Object.new
|
57
|
+
|
58
|
+
require 'concurrent/actor/behaviour/abstract'
|
59
|
+
require 'concurrent/actor/behaviour/awaits'
|
60
|
+
require 'concurrent/actor/behaviour/buffer'
|
61
|
+
require 'concurrent/actor/behaviour/errors_on_unknown_message'
|
62
|
+
require 'concurrent/actor/behaviour/executes_context'
|
63
|
+
require 'concurrent/actor/behaviour/linking'
|
64
|
+
require 'concurrent/actor/behaviour/pausing'
|
65
|
+
require 'concurrent/actor/behaviour/removes_child'
|
66
|
+
require 'concurrent/actor/behaviour/sets_results'
|
67
|
+
require 'concurrent/actor/behaviour/supervising'
|
68
|
+
require 'concurrent/actor/behaviour/termination'
|
69
|
+
require 'concurrent/actor/behaviour/terminates_children'
|
70
|
+
|
71
|
+
# Array of behaviours and their construction parameters.
|
72
|
+
#
|
73
|
+
# [[Behaviour::SetResults, :terminate!],
|
74
|
+
# [Behaviour::RemovesChild],
|
75
|
+
# [Behaviour::Termination],
|
76
|
+
# [Behaviour::TerminatesChildren],
|
77
|
+
# [Behaviour::Linking],
|
78
|
+
# [Behaviour::Awaits],
|
79
|
+
# [Behaviour::ExecutesContext],
|
80
|
+
# [Behaviour::ErrorsOnUnknownMessage]]
|
81
|
+
#
|
82
|
+
# @see '' its source code
|
83
|
+
def self.basic_behaviour_definition
|
84
|
+
[*base(:terminate!),
|
85
|
+
*linking,
|
86
|
+
*user_messages]
|
87
|
+
end
|
88
|
+
|
89
|
+
# Array of behaviours and their construction parameters.
|
90
|
+
#
|
91
|
+
# [[Behaviour::SetResults, :pause!],
|
92
|
+
# [Behaviour::RemovesChild],
|
93
|
+
# [Behaviour::Termination],
|
94
|
+
# [Behaviour::TerminatesChildren],
|
95
|
+
# [Behaviour::Linking],
|
96
|
+
# [Behaviour::Pausing],
|
97
|
+
# [Behaviour::Supervising, :reset!, :one_for_one],
|
98
|
+
# [Behaviour::Awaits],
|
99
|
+
# [Behaviour::ExecutesContext],
|
100
|
+
# [Behaviour::ErrorsOnUnknownMessage]]
|
101
|
+
#
|
102
|
+
# @see '' its source code
|
103
|
+
def self.restarting_behaviour_definition(handle = :reset!, strategy = :one_for_one)
|
104
|
+
[*base(:pause!),
|
105
|
+
*linking,
|
106
|
+
*supervised,
|
107
|
+
*supervising(handle, strategy),
|
108
|
+
*user_messages]
|
109
|
+
end
|
110
|
+
|
111
|
+
# @see '' its source code
|
112
|
+
def self.base(on_error)
|
113
|
+
[[SetResults, on_error],
|
114
|
+
# has to be before Termination to be able to remove children from terminated actor
|
115
|
+
RemovesChild,
|
116
|
+
Termination,
|
117
|
+
TerminatesChildren]
|
118
|
+
end
|
119
|
+
|
120
|
+
# @see '' its source code
|
121
|
+
def self.linking
|
122
|
+
[Linking]
|
123
|
+
end
|
124
|
+
|
125
|
+
# @see '' its source code
|
126
|
+
def self.supervised
|
127
|
+
[Pausing]
|
128
|
+
end
|
129
|
+
|
130
|
+
# @see '' its source code
|
131
|
+
def self.supervising(handle = :reset!, strategy = :one_for_one)
|
132
|
+
[[Behaviour::Supervising, handle, strategy]]
|
133
|
+
end
|
134
|
+
|
135
|
+
# @see '' its source code
|
136
|
+
def self.user_messages
|
137
|
+
[Awaits,
|
138
|
+
ExecutesContext,
|
139
|
+
ErrorsOnUnknownMessage]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|