concurrent-ruby 0.8.0 → 0.9.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +97 -2
- data/README.md +103 -54
- data/lib/concurrent.rb +34 -14
- data/lib/concurrent/async.rb +164 -50
- data/lib/concurrent/atom.rb +171 -0
- data/lib/concurrent/atomic/atomic_boolean.rb +57 -107
- data/lib/concurrent/atomic/atomic_fixnum.rb +73 -101
- data/lib/concurrent/atomic/atomic_reference.rb +49 -0
- data/lib/concurrent/atomic/condition.rb +23 -12
- data/lib/concurrent/atomic/count_down_latch.rb +23 -21
- data/lib/concurrent/atomic/cyclic_barrier.rb +47 -47
- data/lib/concurrent/atomic/event.rb +33 -42
- data/lib/concurrent/atomic/read_write_lock.rb +252 -0
- data/lib/concurrent/atomic/semaphore.rb +64 -89
- data/lib/concurrent/atomic/thread_local_var.rb +130 -58
- data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +236 -0
- data/lib/concurrent/atomic_reference/direct_update.rb +3 -0
- data/lib/concurrent/atomic_reference/jruby.rb +6 -3
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +10 -32
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +3 -0
- data/lib/concurrent/atomic_reference/rbx.rb +4 -1
- data/lib/concurrent/atomic_reference/ruby.rb +6 -3
- data/lib/concurrent/atomics.rb +74 -4
- data/lib/concurrent/collection/copy_on_notify_observer_set.rb +115 -0
- data/lib/concurrent/collection/copy_on_write_observer_set.rb +119 -0
- data/lib/concurrent/collection/priority_queue.rb +300 -245
- data/lib/concurrent/concern/deprecation.rb +27 -0
- data/lib/concurrent/concern/dereferenceable.rb +88 -0
- data/lib/concurrent/concern/logging.rb +25 -0
- data/lib/concurrent/concern/obligation.rb +228 -0
- data/lib/concurrent/concern/observable.rb +85 -0
- data/lib/concurrent/configuration.rb +226 -112
- data/lib/concurrent/dataflow.rb +2 -3
- data/lib/concurrent/delay.rb +141 -50
- data/lib/concurrent/edge.rb +30 -0
- data/lib/concurrent/errors.rb +10 -0
- data/lib/concurrent/exchanger.rb +25 -1
- data/lib/concurrent/executor/cached_thread_pool.rb +46 -33
- data/lib/concurrent/executor/executor.rb +46 -299
- data/lib/concurrent/executor/executor_service.rb +521 -0
- data/lib/concurrent/executor/fixed_thread_pool.rb +206 -26
- data/lib/concurrent/executor/immediate_executor.rb +9 -9
- data/lib/concurrent/executor/indirect_immediate_executor.rb +4 -3
- data/lib/concurrent/executor/java_cached_thread_pool.rb +18 -16
- data/lib/concurrent/executor/java_fixed_thread_pool.rb +11 -18
- data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
- data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
- data/lib/concurrent/executor/ruby_cached_thread_pool.rb +9 -18
- data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +10 -21
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
- data/lib/concurrent/executor/safe_task_executor.rb +5 -4
- data/lib/concurrent/executor/serialized_execution.rb +22 -18
- data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
- data/lib/concurrent/executor/single_thread_executor.rb +32 -21
- data/lib/concurrent/executor/thread_pool_executor.rb +72 -60
- data/lib/concurrent/executor/timer_set.rb +96 -84
- data/lib/concurrent/executors.rb +1 -1
- data/lib/concurrent/future.rb +70 -38
- data/lib/concurrent/immutable_struct.rb +89 -0
- data/lib/concurrent/ivar.rb +152 -60
- data/lib/concurrent/lazy_register.rb +40 -20
- data/lib/concurrent/maybe.rb +226 -0
- data/lib/concurrent/mutable_struct.rb +227 -0
- data/lib/concurrent/mvar.rb +44 -43
- data/lib/concurrent/promise.rb +208 -134
- data/lib/concurrent/scheduled_task.rb +339 -43
- data/lib/concurrent/settable_struct.rb +127 -0
- data/lib/concurrent/synchronization.rb +17 -0
- data/lib/concurrent/synchronization/abstract_object.rb +163 -0
- data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
- data/lib/concurrent/synchronization/condition.rb +53 -0
- data/lib/concurrent/synchronization/java_object.rb +35 -0
- data/lib/concurrent/synchronization/lock.rb +32 -0
- data/lib/concurrent/synchronization/monitor_object.rb +24 -0
- data/lib/concurrent/synchronization/mutex_object.rb +43 -0
- data/lib/concurrent/synchronization/object.rb +78 -0
- data/lib/concurrent/synchronization/rbx_object.rb +75 -0
- data/lib/concurrent/timer_task.rb +87 -100
- data/lib/concurrent/tvar.rb +42 -38
- data/lib/concurrent/utilities.rb +3 -1
- data/lib/concurrent/utility/at_exit.rb +97 -0
- data/lib/concurrent/utility/engine.rb +40 -0
- data/lib/concurrent/utility/monotonic_time.rb +59 -0
- data/lib/concurrent/utility/native_extension_loader.rb +56 -0
- data/lib/concurrent/utility/processor_counter.rb +156 -0
- data/lib/concurrent/utility/timeout.rb +18 -14
- data/lib/concurrent/utility/timer.rb +11 -6
- data/lib/concurrent/version.rb +2 -1
- data/lib/concurrent_ruby.rb +1 -0
- metadata +47 -83
- data/lib/concurrent/actor.rb +0 -103
- data/lib/concurrent/actor/behaviour.rb +0 -70
- data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
- data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
- data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
- data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
- data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
- data/lib/concurrent/actor/behaviour/linking.rb +0 -45
- data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
- data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
- data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
- data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
- data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
- data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
- data/lib/concurrent/actor/behaviour/termination.rb +0 -54
- data/lib/concurrent/actor/context.rb +0 -154
- data/lib/concurrent/actor/core.rb +0 -217
- data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
- data/lib/concurrent/actor/envelope.rb +0 -41
- data/lib/concurrent/actor/errors.rb +0 -27
- data/lib/concurrent/actor/internal_delegations.rb +0 -49
- data/lib/concurrent/actor/public_delegations.rb +0 -40
- data/lib/concurrent/actor/reference.rb +0 -81
- data/lib/concurrent/actor/root.rb +0 -37
- data/lib/concurrent/actor/type_check.rb +0 -48
- data/lib/concurrent/actor/utils.rb +0 -10
- data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
- data/lib/concurrent/actor/utils/balancer.rb +0 -42
- data/lib/concurrent/actor/utils/broadcast.rb +0 -52
- data/lib/concurrent/actor/utils/pool.rb +0 -59
- data/lib/concurrent/actress.rb +0 -3
- data/lib/concurrent/agent.rb +0 -209
- data/lib/concurrent/atomic.rb +0 -92
- data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
- data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
- data/lib/concurrent/atomic/synchronization.rb +0 -51
- data/lib/concurrent/channel/buffered_channel.rb +0 -85
- data/lib/concurrent/channel/channel.rb +0 -41
- data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
- data/lib/concurrent/channel/waitable_list.rb +0 -40
- data/lib/concurrent/channels.rb +0 -5
- data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
- data/lib/concurrent/collection/ring_buffer.rb +0 -59
- data/lib/concurrent/collections.rb +0 -3
- data/lib/concurrent/dereferenceable.rb +0 -108
- data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
- data/lib/concurrent/logging.rb +0 -20
- data/lib/concurrent/obligation.rb +0 -171
- data/lib/concurrent/observable.rb +0 -73
- data/lib/concurrent/options_parser.rb +0 -52
- data/lib/concurrent/utility/processor_count.rb +0 -152
- data/lib/extension_helper.rb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e100cda902e2d18d80d34e38ec541d11bde399a
|
4
|
+
data.tar.gz: a56ad16d5a76aa677befbdf3ad2f7b47b0cc1fcb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 066dcc901e922bb751c79acf6249b693984cda1674adf40efc7dbdd782ca22ff8f313dd4674d282b9b22721522ab03aa481c93399fc94017cc8d90a4c17e2acf
|
7
|
+
data.tar.gz: 36d5fe13bebec7e07b3639c65deb455d0bbcb091a11678c05c8664213573179117517d3f2f097d6413a9f71fc09e1193b8ec189ccaa6d1c422779994638015cd
|
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,106 @@
|
|
1
|
-
### Next Release v0.
|
1
|
+
### Next Release v0.9.0 (Target Date: 7 June 2015)
|
2
|
+
|
3
|
+
* Pure Java implementations of
|
4
|
+
- `AtomicBoolean`
|
5
|
+
- `AtomicFixnum`
|
6
|
+
- `Semaphore`
|
7
|
+
* Fixed bug when pruning Ruby thread pools
|
8
|
+
* Fixed bug in time calculations within `ScheduledTask`
|
9
|
+
* Default `count` in `CountDownLatch` to 1
|
10
|
+
* Use monotonic clock for all timers via `Concurrent.monotonic_time`
|
11
|
+
- Use `Process.clock_gettime(Process::CLOCK_MONOTONIC)` when available
|
12
|
+
- Fallback to `java.lang.System.nanoTime()` on unsupported JRuby versions
|
13
|
+
- Pure Ruby implementation for everything else
|
14
|
+
- Effects `Concurrent.timer`, `Concurrent.timeout`, `TimerSet`, `TimerTask`, and `ScheduledTask`
|
15
|
+
* Deprecated all clock-time based timer scheduling
|
16
|
+
- Only support scheduling by delay
|
17
|
+
- Effects `Concurrent.timer`, `TimerSet`, and `ScheduledTask`
|
18
|
+
* Added new `ReadWriteLock` class
|
19
|
+
* Consistent `at_exit` behavior for Java and Ruby thread pools.
|
20
|
+
* Added `at_exit` handler to Ruby thread pools (already in Java thread pools)
|
21
|
+
- Ruby handler stores the object id and retrieves from `ObjectSpace`
|
22
|
+
- JRuby disables `ObjectSpace` by default so that handler stores the object reference
|
23
|
+
* Added a `:stop_on_exit` option to thread pools to enable/disable `at_exit` handler
|
24
|
+
* Updated thread pool docs to better explain shutting down thread pools
|
25
|
+
* Simpler `:executor` option syntax for all abstractions which support this option
|
26
|
+
* Added `Executor#auto_terminate?` predicate method (for thread pools)
|
27
|
+
* Added `at_exit` handler to `TimerSet`
|
28
|
+
* Simplified auto-termination of the global executors
|
29
|
+
- Can now disable auto-termination of global executors
|
30
|
+
- Added shutdown/kill/wait_for_termination variants for global executors
|
31
|
+
* Can now disable auto-termination for *all* executors (the nuclear option)
|
32
|
+
* Simplified auto-termination of the global executors
|
33
|
+
* Deprecated terms "task pool" and "operation pool"
|
34
|
+
- New terms are "io executor" and "fast executor"
|
35
|
+
- New functions added with new names
|
36
|
+
- Deprecation warnings added to functions referencing old names
|
37
|
+
* Moved all thread pool related functions from `Concurrent::Configuration` to `Concurrent`
|
38
|
+
- Old functions still exist with deprecation warnings
|
39
|
+
- New functions have updated names as appropriate
|
40
|
+
* All high-level abstractions default to the "io executor"
|
41
|
+
* Fixed bug in `Actor` causing it to prematurely warm global thread pools on gem load
|
42
|
+
- This also fixed a `RejectedExecutionError` bug when running with minitest/autorun via JRuby
|
43
|
+
* Moved global logger up to the `Concurrent` namespace and refactored the code
|
44
|
+
* Optimized the performance of `Delay`
|
45
|
+
- Fixed a bug in which no executor option on construction caused block execution on a global thread pool
|
46
|
+
* Numerous improvements and bug fixes to `TimerSet`
|
47
|
+
* Fixed deadlock of `Future` when the handler raises Exception
|
48
|
+
* Added shared specs for more classes
|
49
|
+
* New concurrency abstractions including:
|
50
|
+
- `Atom`
|
51
|
+
- `Maybe`
|
52
|
+
- `ImmutableStruct`
|
53
|
+
- `MutableStruct`
|
54
|
+
- `SettableStruct`
|
55
|
+
* Created an Edge gem for unstable abstractions including
|
56
|
+
- `Actor`
|
57
|
+
- `Agent`
|
58
|
+
- `Channel`
|
59
|
+
- `Exchanger`
|
60
|
+
- `LazyRegister`
|
61
|
+
- **new Future Framework** <http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Edge.html> - unified
|
62
|
+
implementation of Futures and Promises which combines Features of previous `Future`,
|
63
|
+
`Promise`, `IVar`, `Event`, `Probe`, `dataflow`, `Delay`, `TimerTask` into single framework. It uses extensively
|
64
|
+
new synchronization layer to make all the paths **lock-free** with exception of blocking threads on `#wait`.
|
65
|
+
It offers better performance and does not block threads when not required.
|
66
|
+
* Actor framework changes:
|
67
|
+
- fixed reset loop in Pool
|
68
|
+
- Pool can use any actor as a worker, abstract worker class is no longer needed.
|
69
|
+
- Actor events not have format `[:event_name, *payload]` instead of just the Symbol.
|
70
|
+
- Actor now uses new Future/Promise Framework instead of `IVar` for better interoperability
|
71
|
+
- Behaviour definition array was simplified to `[BehaviourClass1, [BehaviourClass2, *initialization_args]]`
|
72
|
+
- Linking behavior responds to :linked message by returning array of linked actors
|
73
|
+
- Supervised behavior is removed in favour of just Linking
|
74
|
+
- RestartingContext is supervised by default now, `supervise: true` is not required any more
|
75
|
+
- Events can be private and public, so far only difference is that Linking will
|
76
|
+
pass to linked actors only public messages. Adding private :restarting and
|
77
|
+
:resetting events which are send before the actor restarts or resets allowing
|
78
|
+
to add callbacks to cleanup current child actors.
|
79
|
+
- Print also object_id in Reference to_s
|
80
|
+
- Add AbstractContext#default_executor to be able to override executor class wide
|
81
|
+
- Add basic IO example
|
82
|
+
- Documentation somewhat improved
|
83
|
+
- All messages should have same priority. It's now possible to send `actor << job1 << job2 << :terminate!` and
|
84
|
+
be sure that both jobs are processed first.
|
85
|
+
* Refactored `Channel` to use newer synchronization objects
|
86
|
+
* Added `#reset` and `#cancel` methods to `TimerSet`
|
87
|
+
* Added `#cancel` method to `Future` and `ScheduledTask`
|
88
|
+
* Refactored `TimerSet` to use `ScheduledTask`
|
89
|
+
* Updated `Async` with a factory that initializes the object
|
90
|
+
* Deprecated `Concurrent.timer` and `Concurrent.timeout`
|
91
|
+
* Reduced max threads on pure-Ruby thread pools (abends around 14751 threads)
|
92
|
+
* Moved many private/internal classes/modules into "namespace" modules
|
93
|
+
* Removed brute-force killing of threads in tests
|
94
|
+
* Fixed a thread pool bug when the operating system cannot allocate more threads
|
95
|
+
|
96
|
+
## Current Release v0.8.0 (25 January 2015)
|
2
97
|
|
3
98
|
* C extension for MRI have been extracted into the `concurrent-ruby-ext` companion gem.
|
4
99
|
Please see the README for more detail.
|
5
100
|
* Better variable isolation in `Promise` and `Future` via an `:args` option
|
6
101
|
* Continued to update intermittently failing tests
|
7
102
|
|
8
|
-
|
103
|
+
### Release v0.7.2 (24 January 2015)
|
9
104
|
|
10
105
|
* New `Semaphore` class based on [java.util.concurrent.Semaphore](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html)
|
11
106
|
* New `Promise.all?` and `Promise.any?` class methods
|
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
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) [![
|
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
3
|
|
4
4
|
<table>
|
5
5
|
<tr>
|
@@ -50,52 +50,91 @@ We also have a [mailing list](http://groups.google.com/group/concurrent-ruby).
|
|
50
50
|
|
51
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
52
|
|
53
|
-
|
53
|
+
#### General-purpose Concurrency Abstractions
|
54
54
|
|
55
|
-
* [Actor](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Actor.html): Implements the Actor Model, where concurrent actors exchange messages.
|
56
|
-
* [Agent](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Agent.html): A single atomic value that represents an identity.
|
57
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.
|
58
57
|
* [Future](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Future.html): An asynchronous operation that produces a value.
|
59
|
-
* [Dataflow](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent
|
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.
|
60
59
|
* [Promise](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promise.html): Similar to Futures, with more features.
|
61
60
|
* [ScheduledTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ScheduledTask.html): Like a Future scheduled for a specific future time.
|
62
61
|
* [TimerTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TimerTask.html): A Thread that periodically wakes up to perform work at regular intervals.
|
63
|
-
* [Channel](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Channel.html): Communicating Sequential Processes (CSP).
|
64
62
|
|
65
|
-
|
63
|
+
#### Thread-safe Value Objects
|
66
64
|
|
67
|
-
*
|
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).
|
68
69
|
|
69
|
-
|
70
|
+
#### Thread-safe Structures
|
70
71
|
|
71
|
-
|
72
|
-
* [CopyOnNotifyObserverSet](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CopyOnNotifyObserverSet.html)
|
73
|
-
* [CopyOnWriteObserverSet](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CopyOnWriteObserverSet.html)
|
72
|
+
Derived from Ruby's [Struct](http://ruby-doc.org/core-2.2.0/Struct.html):
|
74
73
|
|
75
|
-
|
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.
|
76
77
|
|
77
|
-
|
78
|
+
#### Java-inspired ThreadPools and Other Executors
|
78
79
|
|
79
|
-
* [
|
80
|
-
* [countdown latch](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CountDownLatch.html)
|
81
|
-
* [cyclic barrier](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CyclicBarrier.html)
|
82
|
-
* [event](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Event.html)
|
83
|
-
* [exchanger](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Exchanger.html)
|
84
|
-
* [semaphore](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Semaphore.html)
|
85
|
-
* [timeout](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent.html#timeout-class_method)
|
86
|
-
* [timer](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent.html#timer-class_method)
|
80
|
+
* See [ThreadPool](http://ruby-concurrency.github.io/concurrent-ruby/file.thread_pools.html) overview, which also contains a list of other Executors available.
|
87
81
|
|
88
|
-
|
82
|
+
#### Thread Synchronization Classes and Algorithms
|
89
83
|
|
90
|
-
|
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
|
91
90
|
|
92
91
|
* [AtomicBoolean](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/AtomicBoolean.html)
|
93
92
|
* [AtomicFixnum](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/AtomicFixnum.html)
|
94
|
-
* AtomicReference
|
93
|
+
* [AtomicReference](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MutexAtomic.html)
|
95
94
|
* [I-Structures](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/IVar.html) (IVar)
|
96
95
|
* [M-Structures](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MVar.html) (MVar)
|
97
|
-
* [
|
98
|
-
* [
|
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.
|
99
138
|
|
100
139
|
## Usage
|
101
140
|
|
@@ -112,29 +151,39 @@ require 'concurrent' # everything
|
|
112
151
|
|
113
152
|
# groups
|
114
153
|
|
115
|
-
require 'concurrent/actor' # Concurrent::Actor and supporting code
|
116
154
|
require 'concurrent/atomics' # atomic and thread synchronization classes
|
117
|
-
require 'concurrent/channels' # Concurrent::Channel and supporting code
|
118
155
|
require 'concurrent/executors' # Thread pools and other executors
|
119
|
-
require 'concurrent/utilities' # utility methods such as processor count and timers
|
120
156
|
|
121
157
|
# individual abstractions
|
122
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
|
123
179
|
require 'concurrent/agent' # Concurrent::Agent
|
124
|
-
require 'concurrent/
|
125
|
-
require 'concurrent/atomic' # Concurrent::Atomic (formerly the `atomic` gem)
|
126
|
-
require 'concurrent/dataflow' # Concurrent::dataflow
|
127
|
-
require 'concurrent/delay' # Concurrent::Delay
|
180
|
+
require 'concurrent/channel ' # Concurrent::Channel and supporting code
|
128
181
|
require 'concurrent/exchanger' # Concurrent::Exchanger
|
129
|
-
require 'concurrent/
|
130
|
-
require 'concurrent/ivar' # Concurrent::IVar
|
131
|
-
require 'concurrent/mvar' # Concurrent::MVar
|
132
|
-
require 'concurrent/promise' # Concurrent::Promise
|
133
|
-
require 'concurrent/scheduled_task' # Concurrent::ScheduledTask
|
134
|
-
require 'concurrent/timer_task' # Concurrent::TimerTask
|
135
|
-
require 'concurrent/tvar' # Concurrent::TVar
|
182
|
+
require 'concurrent/lazy_register' # Concurrent::LazyRegister
|
136
183
|
```
|
137
184
|
|
185
|
+
If the library does not behave as expected, `Concurrent.use_stdlib_logger(Logger::DEBUG)` could help to reveal the problem.
|
186
|
+
|
138
187
|
## Installation
|
139
188
|
|
140
189
|
```shell
|
@@ -153,8 +202,8 @@ and run `bundle install` from your shell.
|
|
153
202
|
|
154
203
|
Potential performance improvements may be achieved under MRI by installing optional C extensions.
|
155
204
|
To minimize installation errors the C extensions are available in the `concurrent-ruby-ext` extension
|
156
|
-
gem.
|
157
|
-
Simply install the extension
|
205
|
+
gem. `concurrent-ruby` and `concurrent-ruby-ext` are always released together with same version.
|
206
|
+
Simply install the extension gem too:
|
158
207
|
|
159
208
|
```ruby
|
160
209
|
gem install concurrent-ruby-ext
|
@@ -191,22 +240,22 @@ any platform. *Documentation is forthcoming...*
|
|
191
240
|
|
192
241
|
```
|
193
242
|
*MRI only*
|
194
|
-
rake build:native # Build concurrent-ruby-ext-<version>-<platform>.gem into the pkg
|
195
|
-
rake compile:extension # Compile extension
|
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
|
196
245
|
|
197
246
|
*JRuby only*
|
198
|
-
rake build # Build JRuby-specific core gem (alias for `build:core`)
|
199
|
-
rake build:core # Build concurrent-ruby-<version>-java.gem into the pkg directory
|
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
|
200
249
|
|
201
250
|
*All except JRuby*
|
202
|
-
rake build # Build core and extension gems
|
203
|
-
rake build:core # Build concurrent-ruby-<version>.gem into the pkg directory
|
204
|
-
rake build:ext # Build concurrent-ruby-ext-<version>.gem into the pkg directory
|
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
|
205
254
|
|
206
255
|
*All*
|
207
|
-
rake clean # Remove any temporary products
|
208
|
-
rake clobber # Remove any generated file
|
209
|
-
rake compile # Compile all the extensions
|
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
|
210
259
|
```
|
211
260
|
|
212
261
|
## Maintainers
|
@@ -218,7 +267,7 @@ rake compile # Compile all the extensions
|
|
218
267
|
* [Petr Chalupa](https://github.com/pitr-ch)
|
219
268
|
* [Paweł Obrok](https://github.com/obrok)
|
220
269
|
|
221
|
-
|
270
|
+
## Contributing
|
222
271
|
|
223
272
|
1. Fork it
|
224
273
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
data/lib/concurrent.rb
CHANGED
@@ -1,39 +1,59 @@
|
|
1
1
|
require 'concurrent/version'
|
2
2
|
|
3
|
+
require 'concurrent/synchronization'
|
4
|
+
|
3
5
|
require 'concurrent/configuration'
|
4
6
|
|
5
7
|
require 'concurrent/atomics'
|
6
|
-
require 'concurrent/
|
7
|
-
require 'concurrent/collections'
|
8
|
+
require 'concurrent/errors'
|
8
9
|
require 'concurrent/executors'
|
9
10
|
require 'concurrent/utilities'
|
10
11
|
|
11
|
-
require 'concurrent/
|
12
|
-
require 'concurrent/
|
13
|
-
require 'concurrent/lazy_register'
|
14
|
-
require 'concurrent/agent'
|
12
|
+
require 'concurrent/atomic/atomic_reference'
|
13
|
+
require 'concurrent/atom'
|
15
14
|
require 'concurrent/async'
|
16
15
|
require 'concurrent/dataflow'
|
17
16
|
require 'concurrent/delay'
|
18
|
-
require 'concurrent/dereferenceable'
|
19
|
-
require 'concurrent/errors'
|
20
|
-
require 'concurrent/exchanger'
|
21
17
|
require 'concurrent/future'
|
18
|
+
require 'concurrent/immutable_struct'
|
22
19
|
require 'concurrent/ivar'
|
20
|
+
require 'concurrent/maybe'
|
21
|
+
require 'concurrent/mutable_struct'
|
23
22
|
require 'concurrent/mvar'
|
24
|
-
require 'concurrent/obligation'
|
25
|
-
require 'concurrent/observable'
|
26
|
-
require 'concurrent/options_parser'
|
27
23
|
require 'concurrent/promise'
|
28
24
|
require 'concurrent/scheduled_task'
|
25
|
+
require 'concurrent/settable_struct'
|
29
26
|
require 'concurrent/timer_task'
|
30
27
|
require 'concurrent/tvar'
|
31
28
|
|
29
|
+
# @!macro [new] internal_implementation_note
|
30
|
+
#
|
31
|
+
# @note **Private Implementation:** This abstraction is a private, internal
|
32
|
+
# implementation detail. It should never be used directly.
|
33
|
+
|
34
|
+
# @!macro [new] monotonic_clock_warning
|
35
|
+
#
|
36
|
+
# @note Time calculations one all platforms and languages are sensitive to
|
37
|
+
# changes to the system clock. To alleviate the potential problems
|
38
|
+
# associated with changing the system clock while an application is running,
|
39
|
+
# most modern operating systems provide a monotonic clock that operates
|
40
|
+
# independently of the system clock. A monotonic clock cannot be used to
|
41
|
+
# determine human-friendly clock times. A monotonic clock is used exclusively
|
42
|
+
# for calculating time intervals. Not all Ruby platforms provide access to an
|
43
|
+
# operating system monotonic clock. On these platforms a pure-Ruby monotonic
|
44
|
+
# clock will be used as a fallback. An operating system monotonic clock is both
|
45
|
+
# faster and more reliable than the pure-Ruby implementation. The pure-Ruby
|
46
|
+
# implementation should be fast and reliable enough for most non-realtime
|
47
|
+
# operations. At this time the common Ruby platforms that provide access to an
|
48
|
+
# operating system monotonic clock are MRI 2.1 and above and JRuby (all versions).
|
49
|
+
#
|
50
|
+
# @see http://linux.die.net/man/3/clock_gettime Linux clock_gettime(3)
|
51
|
+
|
32
52
|
# Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell,
|
33
53
|
# F#, C#, Java, and classic concurrency patterns.
|
34
|
-
#
|
54
|
+
#
|
35
55
|
# The design goals of this gem are:
|
36
|
-
#
|
56
|
+
#
|
37
57
|
# * Stay true to the spirit of the languages providing inspiration
|
38
58
|
# * But implement in a way that makes sense for Ruby
|
39
59
|
# * Keep the semantics as idiomatic Ruby as possible
|
data/lib/concurrent/async.rb
CHANGED
@@ -8,13 +8,92 @@ require 'concurrent/executor/serialized_execution'
|
|
8
8
|
|
9
9
|
module Concurrent
|
10
10
|
|
11
|
-
#
|
11
|
+
# A mixin module that provides simple asynchronous behavior to any standard
|
12
|
+
# class/object or object.
|
13
|
+
#
|
14
|
+
# ```cucumber
|
15
|
+
# Feature:
|
16
|
+
# As a stateful, plain old Ruby class/object
|
17
|
+
# I want safe, asynchronous behavior
|
18
|
+
# So my long-running methods don't block the main thread
|
19
|
+
# ```
|
20
|
+
#
|
21
|
+
# Stateful, mutable objects must be managed carefully when used asynchronously.
|
22
|
+
# But Ruby is an object-oriented language so designing with objects and classes
|
23
|
+
# plays to Ruby's strengths and is often more natural to many Ruby programmers.
|
24
|
+
# The `Async` module is a way to mix simple yet powerful asynchronous capabilities
|
25
|
+
# into any plain old Ruby object or class. These capabilities provide a reasonable
|
26
|
+
# level of thread safe guarantees when used correctly.
|
27
|
+
#
|
28
|
+
# When this module is mixed into a class or object it provides to new methods:
|
29
|
+
# `async` and `await`. These methods are thread safe with respect to the enclosing
|
30
|
+
# object. The former method allows methods to be called asynchronously by posting
|
31
|
+
# to the global thread pool. The latter allows a method to be called synchronously
|
32
|
+
# on the current thread but does so safely with respect to any pending asynchronous
|
33
|
+
# method calls. Both methods return an `Obligation` which can be inspected for
|
34
|
+
# the result of the method call. Calling a method with `async` will return a
|
35
|
+
# `:pending` `Obligation` whereas `await` will return a `:complete` `Obligation`.
|
36
|
+
#
|
37
|
+
# Very loosely based on the `async` and `await` keywords in C#.
|
38
|
+
#
|
39
|
+
# ### An Important Note About Initialization
|
40
|
+
#
|
41
|
+
# > This module depends on several internal stnchronization mechanisms that
|
42
|
+
# > must be initialized prior to calling any of the async/await/executor methods.
|
43
|
+
# > To ensure thread-safe initialization the class `new` method will be made
|
44
|
+
# > private when the `Concurrent::Async` module is included. A factory method
|
45
|
+
# > called `create` will be defined in its place. The `create`factory will
|
46
|
+
# > create a new object instance, passing all arguments to the constructor,
|
47
|
+
# > and will initialize all stnchronization mechanisms. This is the only way
|
48
|
+
# > thread-safe initialization can be guaranteed.
|
49
|
+
#
|
50
|
+
# ### An Important Note About Thread Safe Guarantees
|
51
|
+
#
|
52
|
+
# > Thread safe guarantees can only be made when asynchronous method calls
|
53
|
+
# > are not mixed with synchronous method calls. Use only synchronous calls
|
54
|
+
# > when the object is used exclusively on a single thread. Use only
|
55
|
+
# > `async` and `await` when the object is shared between threads. Once you
|
56
|
+
# > call a method using `async`, you should no longer call any methods
|
57
|
+
# > directly on the object. Use `async` and `await` exclusively from then on.
|
58
|
+
# > With careful programming it is possible to switch back and forth but it's
|
59
|
+
# > also very easy to create race conditions and break your application.
|
60
|
+
# > Basically, it's "async all the way down."
|
61
|
+
#
|
62
|
+
# @example
|
63
|
+
#
|
64
|
+
# class Echo
|
65
|
+
# include Concurrent::Async
|
66
|
+
#
|
67
|
+
# def echo(msg)
|
68
|
+
# sleep(rand)
|
69
|
+
# print "#{msg}\n"
|
70
|
+
# nil
|
71
|
+
# end
|
72
|
+
# end
|
12
73
|
#
|
13
|
-
#
|
74
|
+
# horn = Echo.new #=> NoMethodError: private method `new' called for Echo:Class
|
75
|
+
#
|
76
|
+
# horn = Echo.create
|
77
|
+
# horn.echo('zero') # synchronous, not thread-safe
|
78
|
+
#
|
79
|
+
# horn.async.echo('one') # asynchronous, non-blocking, thread-safe
|
80
|
+
# horn.await.echo('two') # synchronous, blocking, thread-safe
|
14
81
|
#
|
15
|
-
# @see Concurrent::Obligation
|
82
|
+
# @see Concurrent::Concern::Obligation
|
83
|
+
# @see Concurrent::IVar
|
16
84
|
module Async
|
17
85
|
|
86
|
+
# @!method self.create(*args, &block)
|
87
|
+
#
|
88
|
+
# The factory method used to create new instances of the asynchronous
|
89
|
+
# class. Used instead of `new` to ensure proper initialization of the
|
90
|
+
# synchronization mechanisms.
|
91
|
+
#
|
92
|
+
# @param [Array<Object>] args Zero or more arguments to be passed to the
|
93
|
+
# object's initializer.
|
94
|
+
# @param [Proc] bloc Optional block to pass to the object's initializer.
|
95
|
+
# @return [Object] A properly initialized object of the asynchronous class.
|
96
|
+
|
18
97
|
# Check for the presence of a method on an object and determine if a given
|
19
98
|
# set of arguments matches the required arity.
|
20
99
|
#
|
@@ -34,7 +113,9 @@ module Concurrent
|
|
34
113
|
# @see http://www.ruby-doc.org/core-2.1.1/Method.html#method-i-arity Method#arity
|
35
114
|
# @see http://ruby-doc.org/core-2.1.0/Object.html#method-i-respond_to-3F Object#respond_to?
|
36
115
|
# @see http://www.ruby-doc.org/core-2.1.0/BasicObject.html#method-i-method_missing BasicObject#method_missing
|
37
|
-
|
116
|
+
#
|
117
|
+
# @!visibility private
|
118
|
+
def self.validate_argc(obj, method, *args)
|
38
119
|
argc = args.length
|
39
120
|
arity = obj.method(method).arity
|
40
121
|
|
@@ -44,12 +125,36 @@ module Concurrent
|
|
44
125
|
raise ArgumentError.new("wrong number of arguments (#{argc} for #{arity}..*)")
|
45
126
|
end
|
46
127
|
end
|
47
|
-
|
128
|
+
|
129
|
+
# @!visibility private
|
130
|
+
def self.included(base)
|
131
|
+
base.singleton_class.send(:alias_method, :original_new, :new)
|
132
|
+
base.send(:private_class_method, :original_new)
|
133
|
+
base.extend(ClassMethods)
|
134
|
+
super(base)
|
135
|
+
end
|
136
|
+
|
137
|
+
# @!visibility private
|
138
|
+
module ClassMethods
|
139
|
+
|
140
|
+
# @deprecated
|
141
|
+
def new(*args, &block)
|
142
|
+
warn '[DEPRECATED] use the `create` method instead'
|
143
|
+
create(*args, &block)
|
144
|
+
end
|
145
|
+
|
146
|
+
def create(*args, &block)
|
147
|
+
obj = original_new(*args, &block)
|
148
|
+
obj.send(:init_synchronization)
|
149
|
+
obj
|
150
|
+
end
|
151
|
+
end
|
152
|
+
private_constant :ClassMethods
|
48
153
|
|
49
154
|
# Delegates asynchronous, thread-safe method calls to the wrapped object.
|
50
155
|
#
|
51
156
|
# @!visibility private
|
52
|
-
class AsyncDelegator
|
157
|
+
class AsyncDelegator
|
53
158
|
|
54
159
|
# Create a new delegator object wrapping the given delegate,
|
55
160
|
# protecting it with the given serializer, and executing it on the
|
@@ -84,14 +189,11 @@ module Concurrent
|
|
84
189
|
self.define_singleton_method(method) do |*args2|
|
85
190
|
Async::validate_argc(@delegate, method, *args2)
|
86
191
|
ivar = Concurrent::IVar.new
|
87
|
-
value, reason = nil, nil
|
88
192
|
@serializer.post(@executor.value) do
|
89
193
|
begin
|
90
|
-
|
194
|
+
ivar.set(@delegate.send(method, *args2, &block))
|
91
195
|
rescue => reason
|
92
|
-
|
93
|
-
ensure
|
94
|
-
ivar.complete(reason.nil?, value, reason)
|
196
|
+
ivar.fail(reason)
|
95
197
|
end
|
96
198
|
end
|
97
199
|
ivar.value if @blocking
|
@@ -101,6 +203,7 @@ module Concurrent
|
|
101
203
|
self.send(method, *args)
|
102
204
|
end
|
103
205
|
end
|
206
|
+
private_constant :AsyncDelegator
|
104
207
|
|
105
208
|
# Causes the chained method call to be performed asynchronously on the
|
106
209
|
# global thread pool. The method called by this method will return a
|
@@ -115,26 +218,24 @@ module Concurrent
|
|
115
218
|
# library, some edge cases will be missed. For more information see
|
116
219
|
# the documentation for the `validate_argc` method.
|
117
220
|
#
|
118
|
-
#
|
119
|
-
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
221
|
+
# @!macro [attach] async_thread_safety_warning
|
222
|
+
# @note The method call is guaranteed to be thread safe with respect to
|
223
|
+
# all other method calls against the same object that are called with
|
224
|
+
# either `async` or `await`. The mutable nature of Ruby references
|
225
|
+
# (and object orientation in general) prevent any other thread safety
|
226
|
+
# guarantees. Do NOT mix non-protected method calls with protected
|
227
|
+
# method call. Use *only* protected method calls when sharing the object
|
228
|
+
# between threads.
|
125
229
|
#
|
126
230
|
# @return [Concurrent::IVar] the pending result of the asynchronous operation
|
127
231
|
#
|
128
|
-
# @raise [Concurrent::InitializationError] `#init_mutex` has not been called
|
129
232
|
# @raise [NameError] the object does not respond to `method` method
|
130
233
|
# @raise [ArgumentError] the given `args` do not match the arity of `method`
|
131
234
|
#
|
132
235
|
# @see Concurrent::IVar
|
133
236
|
def async
|
134
|
-
raise InitializationError.new('#init_mutex was never called') unless @__async_initialized__
|
135
237
|
@__async_delegator__.value
|
136
238
|
end
|
137
|
-
alias_method :future, :async
|
138
239
|
|
139
240
|
# Causes the chained method call to be performed synchronously on the
|
140
241
|
# current thread. The method called by this method will return an
|
@@ -149,58 +250,71 @@ module Concurrent
|
|
149
250
|
# library, some edge cases will be missed. For more information see
|
150
251
|
# the documentation for the `validate_argc` method.
|
151
252
|
#
|
152
|
-
#
|
153
|
-
# all other method calls against the same object that are called with
|
154
|
-
# either `async` or `await`. The mutable nature of Ruby references
|
155
|
-
# (and object orientation in general) prevent any other thread safety
|
156
|
-
# guarantees. Do NOT mix non-protected method calls with protected
|
157
|
-
# method call. Use *only* protected method calls when sharing the object
|
158
|
-
# between threads.
|
253
|
+
# @!macro async_thread_safety_warning
|
159
254
|
#
|
160
255
|
# @return [Concurrent::IVar] the completed result of the synchronous operation
|
161
256
|
#
|
162
|
-
# @raise [Concurrent::InitializationError] `#init_mutex` has not been called
|
163
257
|
# @raise [NameError] the object does not respond to `method` method
|
164
258
|
# @raise [ArgumentError] the given `args` do not match the arity of `method`
|
165
259
|
#
|
166
260
|
# @see Concurrent::IVar
|
167
261
|
def await
|
168
|
-
raise InitializationError.new('#init_mutex was never called') unless @__async_initialized__
|
169
262
|
@__await_delegator__.value
|
170
263
|
end
|
171
|
-
alias_method :delay, :await
|
172
264
|
|
173
|
-
# Set a new executor
|
265
|
+
# Set a new executor.
|
174
266
|
#
|
175
|
-
# @raise [
|
176
|
-
# @raise [ArgumentError] executor has already been set
|
267
|
+
# @raise [ArgumentError] executor has already been set.
|
177
268
|
def executor=(executor)
|
178
|
-
raise InitializationError.new('#init_mutex was never called') unless @__async_initialized__
|
179
269
|
@__async_executor__.reconfigure { executor } or
|
180
270
|
raise ArgumentError.new('executor has already been set')
|
181
271
|
end
|
182
272
|
|
183
|
-
# Initialize the internal serializer and other
|
184
|
-
# *must* be called from the constructor of the including class or explicitly
|
185
|
-
# by the caller prior to calling any other methods. If `init_mutex` is *not*
|
186
|
-
# called explicitly the async/await/executor methods will raize a
|
187
|
-
# `Concurrent::InitializationError`. This is the only way thread-safe
|
188
|
-
# initialization can be guaranteed.
|
273
|
+
# Initialize the internal serializer and other stnchronization mechanisms.
|
189
274
|
#
|
190
|
-
# @note This method *must* be called
|
191
|
-
#
|
192
|
-
# This is the only way thread-safe initialization can be guaranteed.
|
275
|
+
# @note This method *must* be called immediately upon object construction.
|
276
|
+
# This is the only way thread-safe initialization can be guaranteed.
|
193
277
|
#
|
194
278
|
# @raise [Concurrent::InitializationError] when called more than once
|
279
|
+
#
|
280
|
+
# @!visibility private
|
281
|
+
# @deprecated
|
195
282
|
def init_mutex
|
196
|
-
|
283
|
+
warn '[DEPRECATED] use the `create` method instead'
|
284
|
+
init_synchronization
|
285
|
+
rescue InitializationError
|
286
|
+
# suppress
|
287
|
+
end
|
288
|
+
|
289
|
+
private
|
290
|
+
|
291
|
+
# Initialize the internal serializer and other stnchronization mechanisms.
|
292
|
+
#
|
293
|
+
# @note This method *must* be called immediately upon object construction.
|
294
|
+
# This is the only way thread-safe initialization can be guaranteed.
|
295
|
+
#
|
296
|
+
# @raise [Concurrent::InitializationError] when called more than once
|
297
|
+
#
|
298
|
+
# @!visibility private
|
299
|
+
def init_synchronization
|
300
|
+
return self if @__async_initialized__
|
301
|
+
|
197
302
|
@__async_initialized__ = true
|
198
303
|
serializer = Concurrent::SerializedExecution.new
|
199
|
-
|
200
|
-
@
|
201
|
-
|
202
|
-
|
203
|
-
|
304
|
+
|
305
|
+
@__async_executor__ = Delay.new {
|
306
|
+
Concurrent.global_io_executor
|
307
|
+
}
|
308
|
+
|
309
|
+
@__await_delegator__ = Delay.new {
|
310
|
+
AsyncDelegator.new(self, Delay.new{ Concurrent::ImmediateExecutor.new }, serializer, true)
|
311
|
+
}
|
312
|
+
|
313
|
+
@__async_delegator__ = Delay.new {
|
314
|
+
AsyncDelegator.new(self, @__async_executor__, serializer, false)
|
315
|
+
}
|
316
|
+
|
317
|
+
self
|
204
318
|
end
|
205
319
|
end
|
206
320
|
end
|