1
1
### Simple asynchronous task
2
2
3
3
future = Concurrent . future { sleep 0.1 ; 1 + 1 } # evaluation starts immediately
4
- # => <#Concurrent::Edge::Future:0x7fa1b59bbbb8 pending blocks:[]>
4
+ # => <#Concurrent::Edge::Future:0x7fcc038ca588 pending blocks:[]>
5
5
future . completed? # => false
6
6
# block until evaluated
7
7
future . value # => 2
11
11
### Failing asynchronous task
12
12
13
13
future = Concurrent . future { raise 'Boom' }
14
- # => <#Concurrent::Edge::Future:0x7fa1b59b2fe0 failed blocks:[]>
14
+ # => <#Concurrent::Edge::Future:0x7fcc038c05b0 pending blocks:[]>
15
15
future . value # => nil
16
16
future . value! rescue $! # => #<RuntimeError: Boom>
17
17
future . reason # => #<RuntimeError: Boom>
24
24
head = Concurrent . future { 1 }
25
25
branch1 = head . then ( &:succ )
26
26
branch2 = head . then ( &:succ ) . then ( &:succ )
27
- branch1 . zip ( branch2 ) . value # => [2, 3]
27
+ branch1 . zip ( branch2 ) . value! # => [2, 3]
28
28
( branch1 & branch2 ) . then { |a , b | a + b } . value! # => 5
29
29
( branch1 & branch2 ) . then ( &:+ ) . value! # => 5
30
30
Concurrent . zip ( branch1 , branch2 , branch1 ) . then { |*values | values . reduce &:+ } . value!
31
31
# => 7
32
32
# pick only first completed
33
- ( branch1 | branch2 ) . value # => 2
33
+ ( branch1 | branch2 ) . value! # => 2
34
+
35
+ # auto splat arrays for blocks
36
+ Concurrent . future { [ 1 , 2 ] } . then ( &:+ ) . value! # => 3
34
37
35
38
36
39
### Error handling
47
50
48
51
# will not evaluate until asked by #value or other method requiring completion
49
52
future = Concurrent . delay { 'lazy' }
50
- # => <#Concurrent::Edge::Future:0x7fa1b5948f00 pending blocks:[]>
53
+ # => <#Concurrent::Edge::Future:0x7fcc022afaa0 pending blocks:[]>
51
54
sleep 0.1
52
55
future . completed? # => false
53
56
future . value # => "lazy"
54
57
55
58
# propagates trough chain allowing whole or partial lazy chains
56
59
57
60
head = Concurrent . delay { 1 }
58
- # => <#Concurrent::Edge::Future:0x7fa1b59401c0 pending blocks:[]>
61
+ # => <#Concurrent::Edge::Future:0x7fcc022a5640 pending blocks:[]>
59
62
branch1 = head . then ( &:succ )
60
- # => <#Concurrent::Edge::Future:0x7fa1b5933290 pending blocks:[]>
63
+ # => <#Concurrent::Edge::Future:0x7fcc0229c478 pending blocks:[]>
61
64
branch2 = head . delay . then ( &:succ )
62
- # => <#Concurrent::Edge::Future:0x7fa1b5930c98 pending blocks:[]>
65
+ # => <#Concurrent::Edge::Future:0x7fcc0228f318 pending blocks:[]>
63
66
join = branch1 & branch2
64
- # => <#Concurrent::Edge::ArrayFuture:0x7fa1b592b7c0 pending blocks:[]>
67
+ # => <#Concurrent::Edge::Future:0x7fcc0228de78 pending blocks:[]>
65
68
66
69
sleep 0.1 # nothing will complete # => 0
67
70
[ head , branch1 , branch2 , join ] . map ( &:completed? ) # => [false, false, false, false]
89
92
### Schedule
90
93
91
94
scheduled = Concurrent . schedule ( 0.1 ) { 1 }
92
- # => <#Concurrent::Edge::Future:0x7fa1b49df190 pending blocks:[]>
95
+ # => <#Concurrent::Edge::Future:0x7fcc0385b368 pending blocks:[]>
93
96
94
97
scheduled . completed? # => false
95
98
scheduled . value # available after 0.1sec # => 1
96
99
97
100
# and in chain
98
101
scheduled = Concurrent . delay { 1 } . schedule ( 0.1 ) . then ( &:succ )
99
- # => <#Concurrent::Edge::Future:0x7fa1b49d4ec0 pending blocks:[]>
102
+ # => <#Concurrent::Edge::Future:0x7fcc03843948 pending blocks:[]>
100
103
# will not be scheduled until value is requested
101
104
sleep 0.1
102
105
scheduled . value # returns after another 0.1sec # => 2
105
108
### Completable Future and Event
106
109
107
110
future = Concurrent . future
108
- # => <#Concurrent::Edge::CompletableFuture:0x7fa1b49bce10 pending blocks:[]>
111
+ # => <#Concurrent::Edge::CompletableFuture:0x7fcc0304fdb8 pending blocks:[]>
109
112
event = Concurrent . event
110
- # => <#Concurrent::Edge::CompletableEvent:0x7fa1b49bc118 pending blocks:[]>
113
+ # => <#Concurrent::Edge::CompletableEvent:0x7fcc0304e210 pending blocks:[]>
111
114
112
115
# will be blocked until completed
113
116
t1 = Thread . new { future . value }
114
117
t2 = Thread . new { event . wait }
115
118
116
119
future . success 1
117
- # => <#Concurrent::Edge::CompletableFuture:0x7fa1b49bce10 success blocks:[]>
120
+ # => <#Concurrent::Edge::CompletableFuture:0x7fcc0304fdb8 success blocks:[]>
118
121
future . success 1 rescue $!
119
122
# => #<Concurrent::MultipleAssignmentError: multiple assignment>
120
123
future . try_success 2 # => false
121
124
event . complete
122
- # => <#Concurrent::Edge::CompletableEvent:0x7fa1b49bc118 completed blocks:[]>
125
+ # => <#Concurrent::Edge::CompletableEvent:0x7fcc0304e210 completed blocks:[]>
123
126
124
127
[ t1 , t2 ] . each &:join
125
128
126
129
127
130
### Callbacks
128
131
129
- queue = Queue . new # => #<Thread::Queue:0x007fa1b49acec0 >
132
+ queue = Queue . new # => #<Thread::Queue:0x007fcc03101720 >
130
133
future = Concurrent . delay { 1 + 1 }
131
- # => <#Concurrent::Edge::Future:0x7fa1b49ac150 pending blocks:[]>
134
+ # => <#Concurrent::Edge::Future:0x7fcc030fbaf0 pending blocks:[]>
132
135
133
136
future . on_success { queue << 1 } # evaluated asynchronously
134
- # => <#Concurrent::Edge::Future:0x7fa1b49ac150 pending blocks:[]>
137
+ # => <#Concurrent::Edge::Future:0x7fcc030fbaf0 pending blocks:[]>
135
138
future . on_success! { queue << 2 } # evaluated on completing thread
136
- # => <#Concurrent::Edge::Future:0x7fa1b49ac150 pending blocks:[]>
139
+ # => <#Concurrent::Edge::Future:0x7fcc030fbaf0 pending blocks:[]>
137
140
138
141
queue . empty? # => true
139
142
future . value # => 2
144
147
### Thread-pools
145
148
146
149
Concurrent . future ( :fast ) { 2 } . then ( :io ) { File . read __FILE__ } . wait
147
- # => <#Concurrent::Edge::Future:0x7fa1b498dd18 success blocks:[]>
150
+ # => <#Concurrent::Edge::Future:0x7fcc030e8bd0 success blocks:[]>
148
151
149
152
150
153
### Interoperability with actors
151
154
152
155
actor = Concurrent ::Actor ::Utils ::AdHoc . spawn :square do
153
156
-> v { v ** 2 }
154
157
end
155
- # => #<Concurrent::Actor::Reference /square (Concurrent::Actor::Utils::AdHoc)>
158
+ # => #<Concurrent::Actor::Reference:0x7fcc0223f020 /square (Concurrent::Actor::Utils::AdHoc)>
156
159
157
160
Concurrent .
158
161
future { 2 } .
165
168
166
169
### Interoperability with channels
167
170
168
- ch1 = Concurrent ::Edge ::Channel . new # => #<Concurrent::Edge::Channel:0x007fa1b41c5e28 >
169
- ch2 = Concurrent ::Edge ::Channel . new # => #<Concurrent::Edge::Channel:0x007fa1b41c5338 >
171
+ ch1 = Concurrent ::Edge ::Channel . new # => #<Concurrent::Edge::Channel:0x007fcc021ec6b8 >
172
+ ch2 = Concurrent ::Edge ::Channel . new # => #<Concurrent::Edge::Channel:0x007fcc021e7b18 >
170
173
171
174
result = Concurrent . select ( ch1 , ch2 )
172
- # => <#Concurrent::Edge::CompletableFuture:0x7fa1b41bf4d8 pending blocks:[]>
175
+ # => <#Concurrent::Edge::CompletableFuture:0x7fcc021e6060 pending blocks:[]>
173
176
ch1 . push 1 # => nil
174
177
result . value!
175
- # => [1, #<Concurrent::Edge::Channel:0x007fa1b41c5e28 >]
178
+ # => [1, #<Concurrent::Edge::Channel:0x007fcc021ec6b8 >]
176
179
177
180
Concurrent .
178
181
future { 1 +1 } .
179
182
then_push ( ch1 )
180
- # => <#Concurrent::Edge::Future:0x7fa1b41b6450 pending blocks:[]>
183
+ # => <#Concurrent::Edge::Future:0x7fcc021dc3d0 pending blocks:[]>
181
184
result = Concurrent .
182
185
future { '%02d' } .
183
186
then_select ( ch1 , ch2 ) .
184
187
then { |format , ( value , channel ) | format format , value }
185
- # => <#Concurrent::Edge::Future:0x7fa1b41a7f40 pending blocks:[]>
188
+ # => <#Concurrent::Edge::Future:0x7fcc021cd9e8 pending blocks:[]>
186
189
result . value! # => "02"
187
190
188
191
189
192
### Common use-cases Examples
190
193
191
194
# simple background processing
192
195
Concurrent . future { do_stuff }
193
- # => <#Concurrent::Edge::Future:0x7fa1b4196d08 pending blocks:[]>
196
+ # => <#Concurrent::Edge::Future:0x7fcc021b7530 pending blocks:[]>
194
197
195
198
# parallel background processing
196
199
jobs = 10 . times . map { |i | Concurrent . future { i } }
@@ -207,7 +210,7 @@ def schedule_job
207
210
end # => :schedule_job
208
211
209
212
schedule_job
210
- # => <#Concurrent::Edge::Future:0x7fa1b4147960 pending blocks:[]>
213
+ # => <#Concurrent::Edge::Future:0x7fcc0218faf8 pending blocks:[]>
211
214
@end = true # => true
212
215
213
216
@@ -220,7 +223,7 @@ def schedule_job
220
223
data [ message ]
221
224
end
222
225
end
223
- # => #<Concurrent::Actor::Reference /db (Concurrent::Actor::Utils::AdHoc)>
226
+ # => #<Concurrent::Actor::Reference:0x7fcc0214f458 /db (Concurrent::Actor::Utils::AdHoc)>
224
227
225
228
concurrent_jobs = 11 . times . map do |v |
226
229
Concurrent .
@@ -243,14 +246,14 @@ def schedule_job
243
246
244
247
DB_POOL = Concurrent ::Actor ::Utils ::Pool . spawn! ( 'DB-pool' , pool_size ) do |index |
245
248
# DB connection constructor
246
- Concurrent ::Actor ::Utils ::AdHoc . spawn ( name : "worker-#{ index } " , args : [ data ] ) do
249
+ Concurrent ::Actor ::Utils ::AdHoc . spawn ( name : "worker-#{ index } " , args : [ data ] ) do | data |
247
250
lambda do |message |
248
251
# pretending that this queries a DB
249
252
data [ message ]
250
253
end
251
254
end
252
255
end
253
- # => #<Concurrent::Actor::Reference /DB-pool (Concurrent::Actor::Utils::Pool)>
256
+ # => #<Concurrent::Actor::Reference:0x7fcc02930398 /DB-pool (Concurrent::Actor::Utils::Pool)>
254
257
255
258
concurrent_jobs = 11 . times . map do |v |
256
259
Concurrent .
0 commit comments