concurrent-ruby-edge 0.3.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +552 -0
- data/LICENSE.txt +18 -18
- data/README.md +261 -103
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/abstract.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/awaits.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/buffer.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/errors_on_unknown_message.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/executes_context.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/linking.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/pausing.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/removes_child.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/sets_results.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/supervising.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour/termination.rb +3 -1
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/behaviour.rb +1 -1
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/context.rb +3 -1
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/core.rb +5 -4
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/default_dead_letter_handler.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/envelope.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/errors.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/internal_delegations.rb +3 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/reference.rb +9 -8
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/root.rb +3 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/utils/ad_hoc.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/utils/balancer.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/utils/broadcast.rb +1 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/utils/pool.rb +1 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor.rb +11 -6
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer/base.rb +14 -14
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer/dropping.rb +1 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer/sliding.rb +1 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer/unbuffered.rb +1 -1
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/tick.rb +1 -1
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel.rb +3 -2
- data/lib/concurrent-ruby-edge/concurrent/edge/cancellation.rb +107 -0
- data/lib/concurrent-ruby-edge/concurrent/edge/channel.rb +453 -0
- data/lib/concurrent-ruby-edge/concurrent/edge/erlang_actor.rb +1549 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/edge/lock_free_linked_set/node.rb +2 -2
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/edge/lock_free_linked_set.rb +8 -7
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/edge/lock_free_queue.rb +2 -0
- data/lib/{concurrent → concurrent-ruby-edge/concurrent}/edge/old_channel_integration.rb +2 -0
- data/lib/concurrent-ruby-edge/concurrent/edge/processing_actor.rb +184 -0
- data/lib/concurrent-ruby-edge/concurrent/edge/promises.rb +174 -0
- data/lib/concurrent-ruby-edge/concurrent/edge/throttle.rb +229 -0
- data/lib/concurrent-ruby-edge/concurrent/edge/version.rb +3 -0
- data/lib/concurrent-ruby-edge/concurrent/edge.rb +21 -0
- data/lib/concurrent-ruby-edge/concurrent/executor/wrapping_executor.rb +50 -0
- data/lib/concurrent-ruby-edge/concurrent/lazy_register.rb +83 -0
- data/lib/{concurrent-edge.rb → concurrent-ruby-edge/concurrent-edge.rb} +5 -4
- metadata +71 -67
- data/lib/concurrent/edge/atomic_markable_reference.rb +0 -184
- data/lib/concurrent/edge/cancellation.rb +0 -138
- data/lib/concurrent/edge/lock_free_stack.rb +0 -126
- data/lib/concurrent/edge/processing_actor.rb +0 -161
- data/lib/concurrent/edge/promises.rb +0 -2111
- data/lib/concurrent/edge/throttle.rb +0 -192
- /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/public_delegations.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/type_check.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/actor/utils.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer/buffered.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer/ticker.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer/timer.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/buffer.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/selector/after_clause.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/selector/default_clause.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/selector/error_clause.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/selector/put_clause.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/selector/take_clause.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/channel/selector.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby-edge/concurrent}/edge/lock_free_linked_set/window.rb +0 -0
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'concurrent/actor/type_check'
|
2
|
+
require 'concurrent/actor/public_delegations'
|
3
|
+
|
1
4
|
module Concurrent
|
2
5
|
module Actor
|
3
6
|
|
@@ -35,12 +38,7 @@ module Concurrent
|
|
35
38
|
|
36
39
|
alias_method :<<, :tell
|
37
40
|
|
38
|
-
# @note it's a good practice to use tell whenever possible.
|
39
|
-
# testing and when it returns very shortly. It can lead to deadlock if all threads in
|
40
|
-
# global_io_executor will block on while asking. It's fine to use it form outside of actors and
|
41
|
-
# global_io_executor.
|
42
|
-
#
|
43
|
-
# @note it's a good practice to use {#tell} whenever possible. Results can be send back with other messages.
|
41
|
+
# @note it's a good practice to use {#tell} whenever possible. Results can be sent back with other messages.
|
44
42
|
# Ask should be used only for testing and when it returns very shortly. It can lead to deadlock if all threads in
|
45
43
|
# global_io_executor will block on while asking. It's fine to use it form outside of actors and
|
46
44
|
# global_io_executor.
|
@@ -55,10 +53,13 @@ module Concurrent
|
|
55
53
|
message message, future
|
56
54
|
end
|
57
55
|
|
56
|
+
# @!visibility privated
|
57
|
+
alias_method :ask_op, :ask
|
58
|
+
|
58
59
|
# Sends the message synchronously and blocks until the message
|
59
60
|
# is processed. Raises on error.
|
60
61
|
#
|
61
|
-
# @note it's a good practice to use {#tell} whenever possible. Results can be
|
62
|
+
# @note it's a good practice to use {#tell} whenever possible. Results can be sent back with other messages.
|
62
63
|
# Ask should be used only for testing and when it returns very shortly. It can lead to deadlock if all threads in
|
63
64
|
# global_io_executor will block on while asking. It's fine to use it form outside of actors and
|
64
65
|
# global_io_executor.
|
@@ -89,7 +90,7 @@ module Concurrent
|
|
89
90
|
end
|
90
91
|
|
91
92
|
def to_s
|
92
|
-
|
93
|
+
format '%s %s (%s)>', super[0..-2], path, actor_class
|
93
94
|
end
|
94
95
|
|
95
96
|
alias_method :inspect, :to_s
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# NOTE: finer grained than require 'concurrent/actor' not supported
|
2
|
+
|
1
3
|
require 'concurrent/configuration'
|
2
4
|
require 'concurrent/executor/serialized_execution'
|
3
|
-
require 'concurrent/synchronization'
|
4
5
|
require 'concurrent/edge/promises'
|
5
6
|
|
6
7
|
module Concurrent
|
@@ -10,9 +11,9 @@ module Concurrent
|
|
10
11
|
# TODO supervision tree, pause children on error in parent, pause may need higher priority
|
11
12
|
# TODO more effective executor
|
12
13
|
|
13
|
-
# {include:file:
|
14
|
+
# {include:file:docs-source/actor/main.md}
|
14
15
|
# @api Actor
|
15
|
-
# @!macro
|
16
|
+
# @!macro warn.edge
|
16
17
|
module Actor
|
17
18
|
|
18
19
|
require 'concurrent/actor/type_check'
|
@@ -35,9 +36,13 @@ module Concurrent
|
|
35
36
|
end
|
36
37
|
|
37
38
|
@root = Concurrent::Promises.delay do
|
38
|
-
Core.
|
39
|
-
|
40
|
-
|
39
|
+
Core.
|
40
|
+
new(parent: nil,
|
41
|
+
name: '/',
|
42
|
+
class: Root,
|
43
|
+
initialized: future = Concurrent::Promises.resolvable_future).
|
44
|
+
reference.
|
45
|
+
tap { future.wait! }
|
41
46
|
end
|
42
47
|
|
43
48
|
# A root actor, a default parent of all actors spawned outside an actor
|
@@ -15,13 +15,13 @@ module Concurrent
|
|
15
15
|
# used as a channel buffer should extend this class.
|
16
16
|
class Base < Synchronization::LockableObject
|
17
17
|
|
18
|
-
# @!macro
|
18
|
+
# @!macro channel_buffer_capacity_reader
|
19
19
|
#
|
20
20
|
# The maximum number of values which can be {#put} onto the buffer
|
21
21
|
# it becomes full.
|
22
22
|
attr_reader :capacity
|
23
23
|
|
24
|
-
# @!macro
|
24
|
+
# @!macro channel_buffer_initialize
|
25
25
|
#
|
26
26
|
# Creates a new buffer.
|
27
27
|
def initialize(*args)
|
@@ -35,7 +35,7 @@ module Concurrent
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
# @!macro
|
38
|
+
# @!macro channel_buffer_blocking_question
|
39
39
|
#
|
40
40
|
# Predicate indicating if this buffer will block {#put} operations
|
41
41
|
# once it reaches its maximum capacity.
|
@@ -45,14 +45,14 @@ module Concurrent
|
|
45
45
|
true
|
46
46
|
end
|
47
47
|
|
48
|
-
# @!macro
|
48
|
+
# @!macro channel_buffer_size_reader
|
49
49
|
#
|
50
50
|
# The number of items currently in the buffer.
|
51
51
|
def size
|
52
52
|
synchronize { ns_size }
|
53
53
|
end
|
54
54
|
|
55
|
-
# @!macro
|
55
|
+
# @!macro channel_buffer_empty_question
|
56
56
|
#
|
57
57
|
# Predicate indicating if the buffer is empty.
|
58
58
|
#
|
@@ -63,7 +63,7 @@ module Concurrent
|
|
63
63
|
synchronize { ns_empty? }
|
64
64
|
end
|
65
65
|
|
66
|
-
# @!macro
|
66
|
+
# @!macro channel_buffer_full_question
|
67
67
|
#
|
68
68
|
# Predicate indicating if the buffer is full.
|
69
69
|
#
|
@@ -74,7 +74,7 @@ module Concurrent
|
|
74
74
|
synchronize { ns_full? }
|
75
75
|
end
|
76
76
|
|
77
|
-
# @!macro
|
77
|
+
# @!macro channel_buffer_put
|
78
78
|
#
|
79
79
|
# Put an item onto the buffer if possible. If the buffer is open
|
80
80
|
# but not able to accept the item the calling thread will block
|
@@ -89,9 +89,9 @@ module Concurrent
|
|
89
89
|
raise NotImplementedError
|
90
90
|
end
|
91
91
|
|
92
|
-
# @!macro
|
92
|
+
# @!macro channel_buffer_offer
|
93
93
|
#
|
94
|
-
# Put an item onto the buffer
|
94
|
+
# Put an item onto the buffer if possible. If the buffer is open but
|
95
95
|
# unable to add an item, probably due to being full, the method will
|
96
96
|
# return immediately. Similarly, the method will return immediately
|
97
97
|
# when the buffer is closed. A return value of `false` does not
|
@@ -107,7 +107,7 @@ module Concurrent
|
|
107
107
|
raise NotImplementedError
|
108
108
|
end
|
109
109
|
|
110
|
-
# @!macro
|
110
|
+
# @!macro channel_buffer_take
|
111
111
|
#
|
112
112
|
# Take an item from the buffer if one is available. If the buffer
|
113
113
|
# is open and no item is available the calling thread will block
|
@@ -123,7 +123,7 @@ module Concurrent
|
|
123
123
|
raise NotImplementedError
|
124
124
|
end
|
125
125
|
|
126
|
-
# @!macro
|
126
|
+
# @!macro channel_buffer_next
|
127
127
|
#
|
128
128
|
# Take the next "item" from the buffer and also return a boolean
|
129
129
|
# indicating if "more" items can be taken. Used for iterating
|
@@ -152,7 +152,7 @@ module Concurrent
|
|
152
152
|
raise NotImplementedError
|
153
153
|
end
|
154
154
|
|
155
|
-
# @!macro
|
155
|
+
# @!macro channel_buffer_poll
|
156
156
|
#
|
157
157
|
# Take the next item from the buffer if one is available else return
|
158
158
|
# immediately. Failing to return a value does not necessarily
|
@@ -166,7 +166,7 @@ module Concurrent
|
|
166
166
|
raise NotImplementedError
|
167
167
|
end
|
168
168
|
|
169
|
-
# @!macro
|
169
|
+
# @!macro channel_buffer_close
|
170
170
|
#
|
171
171
|
# Close the buffer, preventing new items from being added. Once a
|
172
172
|
# buffer is closed it cannot be opened again.
|
@@ -179,7 +179,7 @@ module Concurrent
|
|
179
179
|
end
|
180
180
|
end
|
181
181
|
|
182
|
-
# @!macro
|
182
|
+
# @!macro channel_buffer_closed_question
|
183
183
|
#
|
184
184
|
# Predicate indicating is this buffer closed.
|
185
185
|
#
|
@@ -8,13 +8,14 @@ require 'concurrent/executor/cached_thread_pool'
|
|
8
8
|
|
9
9
|
module Concurrent
|
10
10
|
|
11
|
-
# {include:file:
|
11
|
+
# {include:file:docs-source/channel.md}
|
12
|
+
# @!macro warn.edge
|
12
13
|
class Channel
|
13
14
|
extend Forwardable
|
14
15
|
include Enumerable
|
15
16
|
|
16
17
|
# NOTE: Move to global IO pool once stable
|
17
|
-
GOROUTINES = Concurrent::CachedThreadPool.new
|
18
|
+
GOROUTINES = Concurrent::CachedThreadPool.new
|
18
19
|
private_constant :GOROUTINES
|
19
20
|
|
20
21
|
BUFFER_TYPES = {
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'concurrent/concern/deprecation'
|
2
|
+
require 'concurrent/synchronization/object'
|
3
|
+
require 'concurrent/promises'
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
|
7
|
+
# TODO (pitr-ch 27-Mar-2016): cooperation with mutex, condition, select etc?
|
8
|
+
# TODO (pitr-ch 10-Dec-2018): integrate with enumerator?
|
9
|
+
# token.cancelable(array.each_with_index).each do |v, i|
|
10
|
+
# # stops iterating when cancelled
|
11
|
+
# end
|
12
|
+
# token.cancelable(array).each_with_index do |v, i|
|
13
|
+
# # stops iterating when cancelled
|
14
|
+
# end
|
15
|
+
|
16
|
+
# The Cancellation abstraction provides cooperative cancellation.
|
17
|
+
#
|
18
|
+
# The standard methods `Thread#raise` of `Thread#kill` available in Ruby
|
19
|
+
# are very dangerous (see linked the blog posts bellow).
|
20
|
+
# Therefore concurrent-ruby provides an alternative.
|
21
|
+
# * <https://jvns.ca/blog/2015/11/27/why-rubys-timeout-is-dangerous-and-thread-dot-raise-is-terrifying/>
|
22
|
+
# * <http://www.mikeperham.com/2015/05/08/timeout-rubys-most-dangerous-api/>
|
23
|
+
# * <http://blog.headius.com/2008/02/rubys-threadraise-threadkill-timeoutrb.html>
|
24
|
+
#
|
25
|
+
# It provides an object which represents a task which can be executed,
|
26
|
+
# the task has to get the reference to the object and periodically cooperatively check that it is not cancelled.
|
27
|
+
# Good practices to make tasks cancellable:
|
28
|
+
# * check cancellation every cycle of a loop which does significant work,
|
29
|
+
# * do all blocking actions in a loop with a timeout then on timeout check cancellation
|
30
|
+
# and if ok block again with the timeout
|
31
|
+
#
|
32
|
+
# The idea was inspired by <https://msdn.microsoft.com/en-us/library/dd537607(v=vs.110).aspx>
|
33
|
+
# @!macro warn.edge
|
34
|
+
#
|
35
|
+
# {include:file:docs-source/cancellation.out.md}
|
36
|
+
class Cancellation < Synchronization::Object
|
37
|
+
safe_initialization!
|
38
|
+
|
39
|
+
# Create Cancellation which will cancel itself in given time
|
40
|
+
#
|
41
|
+
# @!macro promises.param.intended_time
|
42
|
+
# @return [Cancellation]
|
43
|
+
def self.timeout(intended_time)
|
44
|
+
new Concurrent::Promises.schedule(intended_time)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Creates the cancellation object.
|
48
|
+
#
|
49
|
+
# @param [Promises::Future, Promises::Event] origin of the cancellation.
|
50
|
+
# When it is resolved the cancellation is canceled.
|
51
|
+
# @example
|
52
|
+
# cancellation, origin = Concurrent::Cancellation.new
|
53
|
+
# @see #to_ary
|
54
|
+
def initialize(origin = Promises.resolvable_event)
|
55
|
+
super()
|
56
|
+
@Origin = origin
|
57
|
+
end
|
58
|
+
|
59
|
+
# Allow to multi-assign the Cancellation object
|
60
|
+
# @return [Array(Cancellation, Promises::Future), Array(Cancellation, Promises::Event)]
|
61
|
+
# @example
|
62
|
+
# cancellation = Concurrent::Cancellation.new
|
63
|
+
# cancellation, origin = Concurrent::Cancellation.new
|
64
|
+
def to_ary
|
65
|
+
[self, @Origin]
|
66
|
+
end
|
67
|
+
|
68
|
+
# The event or future which is the origin of the cancellation
|
69
|
+
# @return [Promises::Future, Promises::Event]
|
70
|
+
def origin
|
71
|
+
@Origin
|
72
|
+
end
|
73
|
+
|
74
|
+
# Is the cancellation cancelled?
|
75
|
+
# Respective, was the origin of the cancellation resolved.
|
76
|
+
# @return [true, false]
|
77
|
+
def canceled?
|
78
|
+
@Origin.resolved?
|
79
|
+
end
|
80
|
+
|
81
|
+
# Raise error when cancelled
|
82
|
+
# @param [#exception] error to be risen
|
83
|
+
# @raise the error
|
84
|
+
# @return [self]
|
85
|
+
def check!(error = CancelledOperationError)
|
86
|
+
raise error if canceled?
|
87
|
+
self
|
88
|
+
end
|
89
|
+
|
90
|
+
# Creates a new Cancellation which is cancelled when first
|
91
|
+
# of the supplied cancellations or self is cancelled.
|
92
|
+
#
|
93
|
+
# @param [Cancellation] cancellations to combine
|
94
|
+
# @return [Cancellation] new cancellation
|
95
|
+
def join(*cancellations)
|
96
|
+
Cancellation.new Promises.any_event(*[@Origin, *cancellations.map(&:origin)])
|
97
|
+
end
|
98
|
+
|
99
|
+
# Short string representation.
|
100
|
+
# @return [String]
|
101
|
+
def to_s
|
102
|
+
format '%s %s>', super[0..-2], canceled? ? 'canceled' : 'pending'
|
103
|
+
end
|
104
|
+
|
105
|
+
alias_method :inspect, :to_s
|
106
|
+
end
|
107
|
+
end
|