1
1
### Simple asynchronous task
2
2
3
3
future = Concurrent . future { sleep 0.1 ; 1 + 1 } # evaluation starts immediately
4
- # => <#Concurrent::Edge::Future:0x7f9f549266e8 pending blocks:[]>
4
+ # => <#Concurrent::Edge::Future:0x7fa1b59bbbb8 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:0x7f9f548dd3f8 pending blocks:[]>
14
+ # => <#Concurrent::Edge::Future:0x7fa1b59b2fe0 failed blocks:[]>
15
15
future . value # => nil
16
16
future . value! rescue $! # => #<RuntimeError: Boom>
17
17
future . reason # => #<RuntimeError: Boom>
23
23
24
24
head = Concurrent . future { 1 }
25
25
branch1 = head . then ( &:succ )
26
- branch2 = head . then ( &:succ ) . then ( &:succ )
27
- # zipping futures
26
+ branch2 = head . then ( &:succ ) . then ( &:succ )
28
27
branch1 . zip ( branch2 ) . value # => [2, 3]
29
28
( branch1 & branch2 ) . then { |a , b | a + b } . value! # => 5
30
29
( branch1 & branch2 ) . then ( &:+ ) . value! # => 5
48
47
49
48
# will not evaluate until asked by #value or other method requiring completion
50
49
future = Concurrent . delay { 'lazy' }
51
- # => <#Concurrent::Edge::Future:0x7f9f53a57b58 pending blocks:[]>
50
+ # => <#Concurrent::Edge::Future:0x7fa1b5948f00 pending blocks:[]>
52
51
sleep 0.1
53
52
future . completed? # => false
54
53
future . value # => "lazy"
55
54
56
55
# propagates trough chain allowing whole or partial lazy chains
57
56
58
57
head = Concurrent . delay { 1 }
59
- # => <#Concurrent::Edge::Future:0x7f9f53a35508 pending blocks:[]>
58
+ # => <#Concurrent::Edge::Future:0x7fa1b59401c0 pending blocks:[]>
60
59
branch1 = head . then ( &:succ )
61
- # => <#Concurrent::Edge::Future:0x7f9f53a17328 pending blocks:[]>
60
+ # => <#Concurrent::Edge::Future:0x7fa1b5933290 pending blocks:[]>
62
61
branch2 = head . delay . then ( &:succ )
63
- # => <#Concurrent::Edge::Future:0x7f9f5590d868 pending blocks:[]>
62
+ # => <#Concurrent::Edge::Future:0x7fa1b5930c98 pending blocks:[]>
64
63
join = branch1 & branch2
65
- # => <#Concurrent::Edge::ArrayFuture:0x7f9f558fd7d8 pending blocks:[]>
64
+ # => <#Concurrent::Edge::ArrayFuture:0x7fa1b592b7c0 pending blocks:[]>
66
65
67
66
sleep 0.1 # nothing will complete # => 0
68
67
[ head , branch1 , branch2 , join ] . map ( &:completed? ) # => [false, false, false, false]
90
89
### Schedule
91
90
92
91
scheduled = Concurrent . schedule ( 0.1 ) { 1 }
93
- # => <#Concurrent::Edge::Future:0x7f9f5581ed30 pending blocks:[]>
92
+ # => <#Concurrent::Edge::Future:0x7fa1b49df190 pending blocks:[]>
94
93
95
94
scheduled . completed? # => false
96
95
scheduled . value # available after 0.1sec # => 1
97
96
98
97
# and in chain
99
98
scheduled = Concurrent . delay { 1 } . schedule ( 0.1 ) . then ( &:succ )
100
- # => <#Concurrent::Edge::Future:0x7f9f548494c8 pending blocks:[]>
99
+ # => <#Concurrent::Edge::Future:0x7fa1b49d4ec0 pending blocks:[]>
101
100
# will not be scheduled until value is requested
102
101
sleep 0.1
103
102
scheduled . value # returns after another 0.1sec # => 2
106
105
### Completable Future and Event
107
106
108
107
future = Concurrent . future
109
- # => <#Concurrent::Edge::CompletableFuture:0x7f9f5385bcf0 pending blocks:[]>
108
+ # => <#Concurrent::Edge::CompletableFuture:0x7fa1b49bce10 pending blocks:[]>
110
109
event = Concurrent . event
111
- # => <#Concurrent::Edge::CompletableEvent:0x7f9f53858ca8 pending blocks:[]>
110
+ # => <#Concurrent::Edge::CompletableEvent:0x7fa1b49bc118 pending blocks:[]>
112
111
113
112
# will be blocked until completed
114
113
t1 = Thread . new { future . value }
115
114
t2 = Thread . new { event . wait }
116
115
117
116
future . success 1
118
- # => <#Concurrent::Edge::CompletableFuture:0x7f9f5385bcf0 success blocks:[]>
117
+ # => <#Concurrent::Edge::CompletableFuture:0x7fa1b49bce10 success blocks:[]>
119
118
future . success 1 rescue $!
120
119
# => #<Concurrent::MultipleAssignmentError: multiple assignment>
121
120
future . try_success 2 # => false
122
121
event . complete
123
- # => <#Concurrent::Edge::CompletableEvent:0x7f9f53858ca8 completed blocks:[]>
122
+ # => <#Concurrent::Edge::CompletableEvent:0x7fa1b49bc118 completed blocks:[]>
124
123
125
124
[ t1 , t2 ] . each &:join
126
125
127
126
128
127
### Callbacks
129
128
130
- queue = Queue . new # => #<Thread::Queue:0x007f9f53861b50 >
129
+ queue = Queue . new # => #<Thread::Queue:0x007fa1b49acec0 >
131
130
future = Concurrent . delay { 1 + 1 }
132
- # => <#Concurrent::Edge::Future:0x7f9f54853d10 pending blocks:[]>
131
+ # => <#Concurrent::Edge::Future:0x7fa1b49ac150 pending blocks:[]>
133
132
134
133
future . on_success { queue << 1 } # evaluated asynchronously
135
- # => <#Concurrent::Edge::Future:0x7f9f54853d10 pending blocks:[]>
134
+ # => <#Concurrent::Edge::Future:0x7fa1b49ac150 pending blocks:[]>
136
135
future . on_success! { queue << 2 } # evaluated on completing thread
137
- # => <#Concurrent::Edge::Future:0x7f9f54853d10 pending blocks:[]>
136
+ # => <#Concurrent::Edge::Future:0x7fa1b49ac150 pending blocks:[]>
138
137
139
138
queue . empty? # => true
140
139
future . value # => 2
145
144
### Thread-pools
146
145
147
146
Concurrent . future ( :fast ) { 2 } . then ( :io ) { File . read __FILE__ } . wait
148
- # => <#Concurrent::Edge::Future:0x7f9f539545f8 success blocks:[]>
147
+ # => <#Concurrent::Edge::Future:0x7fa1b498dd18 success blocks:[]>
149
148
150
149
151
150
### Interoperability with actors
166
165
167
166
### Interoperability with channels
168
167
169
- ch1 = Concurrent ::Edge ::Channel . new # => #<Concurrent::Edge::Channel:0x007f9f558e5db8 >
170
- ch2 = Concurrent ::Edge ::Channel . new # => #<Concurrent::Edge::Channel:0x007f9f558e4f80 >
168
+ ch1 = Concurrent ::Edge ::Channel . new # => #<Concurrent::Edge::Channel:0x007fa1b41c5e28 >
169
+ ch2 = Concurrent ::Edge ::Channel . new # => #<Concurrent::Edge::Channel:0x007fa1b41c5338 >
171
170
172
171
result = Concurrent . select ( ch1 , ch2 )
173
- # => <#Concurrent::Edge::CompletableFuture:0x7f9f53a4fe58 pending blocks:[]>
172
+ # => <#Concurrent::Edge::CompletableFuture:0x7fa1b41bf4d8 pending blocks:[]>
174
173
ch1 . push 1 # => nil
175
174
result . value!
176
- # => [1, #<Concurrent::Edge::Channel:0x007f9f558e5db8 >]
175
+ # => [1, #<Concurrent::Edge::Channel:0x007fa1b41c5e28 >]
177
176
178
177
Concurrent .
179
178
future { 1 +1 } .
180
179
then_push ( ch1 )
181
- # => <#Concurrent::Edge::Future:0x7f9f53a2e758 pending blocks:[]>
180
+ # => <#Concurrent::Edge::Future:0x7fa1b41b6450 pending blocks:[]>
182
181
result = Concurrent .
183
182
future { '%02d' } .
184
183
then_select ( ch1 , ch2 ) .
185
184
then { |format , ( value , channel ) | format format , value }
186
- # => <#Concurrent::Edge::Future:0x7f9f55925f30 pending blocks:[]>
185
+ # => <#Concurrent::Edge::Future:0x7fa1b41a7f40 pending blocks:[]>
187
186
result . value! # => "02"
188
187
189
188
190
189
### Common use-cases Examples
191
190
192
191
# simple background processing
193
192
Concurrent . future { do_stuff }
194
- # => <#Concurrent::Edge::Future:0x7f9f53a93e50 pending blocks:[]>
193
+ # => <#Concurrent::Edge::Future:0x7fa1b4196d08 pending blocks:[]>
195
194
196
195
# parallel background processing
197
196
jobs = 10 . times . map { |i | Concurrent . future { i } }
@@ -208,7 +207,7 @@ def schedule_job
208
207
end # => :schedule_job
209
208
210
209
schedule_job
211
- # => <#Concurrent::Edge::Future:0x7f9f548b01a0 pending blocks:[]>
210
+ # => <#Concurrent::Edge::Future:0x7fa1b4147960 pending blocks:[]>
212
211
@end = true # => true
213
212
214
213
@@ -238,24 +237,18 @@ def schedule_job
238
237
239
238
240
239
# In reality there is often a pool though:
241
- class DBConnection < Concurrent ::Actor ::Utils ::AbstractWorker
242
- def initialize ( balancer , data )
243
- super balancer
244
- @data = data
245
- end
246
-
247
- def work ( message )
248
- # pretending that this queries a DB
249
- @data [ message ]
250
- end
251
- end # => :work
252
-
253
240
data = Array . new ( 10 ) { |i | '*' * i }
254
241
# => ["", "*", "**", "***", "****", "*****", "******", "*******", "********", "*********"]
255
242
pool_size = 5 # => 5
256
243
257
- DB_POOL = Concurrent ::Actor ::Utils ::Pool . spawn! ( 'DB-pool' , pool_size ) do |balancer , index |
258
- DBConnection . spawn ( name : "worker-#{ index } " , args : [ balancer , data ] )
244
+ DB_POOL = Concurrent ::Actor ::Utils ::Pool . spawn! ( 'DB-pool' , pool_size ) do |index |
245
+ # DB connection constructor
246
+ Concurrent ::Actor ::Utils ::AdHoc . spawn ( name : "worker-#{ index } " , args : [ data ] ) do
247
+ lambda do |message |
248
+ # pretending that this queries a DB
249
+ data [ message ]
250
+ end
251
+ end
259
252
end
260
253
# => #<Concurrent::Actor::Reference /DB-pool (Concurrent::Actor::Utils::Pool)>
261
254
0 commit comments