async 1.26.1 → 1.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/async/barrier.rb +1 -1
- data/lib/async/version.rb +1 -1
- metadata +54 -99
- data/.editorconfig +0 -6
- data/.github/workflows/development.yml +0 -55
- data/.gitignore +0 -14
- data/.rspec +0 -3
- data/.yardopts +0 -1
- data/Gemfile +0 -20
- data/Guardfile +0 -14
- data/README.md +0 -385
- data/Rakefile +0 -40
- data/async.gemspec +0 -34
- data/bake.rb +0 -33
- data/benchmark/async_vs_lightio.rb +0 -84
- data/benchmark/fiber_count.rb +0 -10
- data/benchmark/rubies/README.md +0 -51
- data/benchmark/rubies/benchmark.rb +0 -220
- data/benchmark/thread_count.rb +0 -9
- data/benchmark/thread_vs_fiber.rb +0 -45
- data/examples/async_method.rb +0 -60
- data/examples/callback/loop.rb +0 -44
- data/examples/capture/README.md +0 -59
- data/examples/capture/capture.rb +0 -116
- data/examples/fibers.rb +0 -178
- data/examples/queue/producer.rb +0 -28
- data/examples/sleep_sort.rb +0 -40
- data/examples/stop/condition.rb +0 -31
- data/examples/stop/sleep.rb +0 -42
- data/gems/event.gemfile +0 -4
- data/logo.png +0 -0
- data/logo.svg +0 -64
- data/papers/1982 Grossman.pdf +0 -0
- data/papers/1987 ODell.pdf +0 -0
- data/spec/async/barrier_spec.rb +0 -116
- data/spec/async/chainable_async_examples.rb +0 -13
- data/spec/async/clock_spec.rb +0 -37
- data/spec/async/condition_examples.rb +0 -105
- data/spec/async/condition_spec.rb +0 -72
- data/spec/async/logger_spec.rb +0 -65
- data/spec/async/node_spec.rb +0 -193
- data/spec/async/notification_spec.rb +0 -66
- data/spec/async/performance_spec.rb +0 -72
- data/spec/async/queue_spec.rb +0 -133
- data/spec/async/reactor/nested_spec.rb +0 -52
- data/spec/async/reactor_spec.rb +0 -253
- data/spec/async/semaphore_spec.rb +0 -169
- data/spec/async/task_spec.rb +0 -476
- data/spec/async/wrapper_spec.rb +0 -203
- data/spec/async_spec.rb +0 -33
- data/spec/enumerator_spec.rb +0 -83
- data/spec/kernel/async_spec.rb +0 -39
- data/spec/kernel/sync_spec.rb +0 -54
- data/spec/spec_helper.rb +0 -18
data/spec/async/task_spec.rb
DELETED
@@ -1,476 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
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.
|
22
|
-
|
23
|
-
require 'async'
|
24
|
-
require 'async/clock'
|
25
|
-
|
26
|
-
RSpec.describe Async::Task do
|
27
|
-
let(:reactor) {Async::Reactor.new}
|
28
|
-
|
29
|
-
describe '#run' do
|
30
|
-
it "can't be invoked twice" do
|
31
|
-
task = reactor.async do |task|
|
32
|
-
end
|
33
|
-
|
34
|
-
expect{task.run}.to raise_exception(RuntimeError, /already running/)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
describe '#current?' do
|
39
|
-
it "can check if it is the currently running task" do
|
40
|
-
task = reactor.async do |task|
|
41
|
-
expect(task).to be_current
|
42
|
-
task.sleep(0.1)
|
43
|
-
end
|
44
|
-
|
45
|
-
expect(task).to_not be_current
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
describe '#async' do
|
50
|
-
it "can start child async tasks" do
|
51
|
-
child = nil
|
52
|
-
|
53
|
-
parent = reactor.async do |task|
|
54
|
-
child = task.async do
|
55
|
-
task.sleep(1)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
expect(parent).to_not be_nil
|
60
|
-
expect(child).to_not be_nil
|
61
|
-
expect(child.parent).to_not be_nil
|
62
|
-
end
|
63
|
-
|
64
|
-
it "can pass in arguments" do
|
65
|
-
reactor.async do |task|
|
66
|
-
task.async(:arg) do |task, arg|
|
67
|
-
expect(arg).to be == :arg
|
68
|
-
end.wait
|
69
|
-
end.wait
|
70
|
-
end
|
71
|
-
|
72
|
-
it "can set initial annotation" do
|
73
|
-
reactor.async(annotation: "Hello World") do |task|
|
74
|
-
expect(task.annotation).to be == "Hello World"
|
75
|
-
end.wait
|
76
|
-
end
|
77
|
-
|
78
|
-
it "can raise exceptions" do
|
79
|
-
expect do
|
80
|
-
reactor.async do |task|
|
81
|
-
raise "boom"
|
82
|
-
end.wait
|
83
|
-
end.to raise_exception RuntimeError, /boom/
|
84
|
-
end
|
85
|
-
|
86
|
-
it "can raise exception after asynchronous operation" do
|
87
|
-
task = nil
|
88
|
-
|
89
|
-
expect do
|
90
|
-
task = reactor.async do |task|
|
91
|
-
task.sleep 0.1
|
92
|
-
|
93
|
-
raise "boom"
|
94
|
-
end
|
95
|
-
end.to_not raise_exception
|
96
|
-
|
97
|
-
reactor.run do
|
98
|
-
expect do
|
99
|
-
task.wait
|
100
|
-
end.to raise_exception RuntimeError, /boom/
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
it "can consume exceptions" do
|
105
|
-
task = nil
|
106
|
-
|
107
|
-
expect do
|
108
|
-
task = reactor.async do |task|
|
109
|
-
raise "boom"
|
110
|
-
end
|
111
|
-
end.to_not raise_exception
|
112
|
-
|
113
|
-
expect do
|
114
|
-
task.wait
|
115
|
-
end.to raise_exception RuntimeError, /boom/
|
116
|
-
end
|
117
|
-
|
118
|
-
it "won't consume non-StandardError exceptions" do
|
119
|
-
expect do
|
120
|
-
reactor.async do |task|
|
121
|
-
raise SignalException.new(:TERM)
|
122
|
-
end
|
123
|
-
end.to raise_exception(SignalException, /TERM/)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
describe '#yield' do
|
128
|
-
it "can yield back to reactor" do
|
129
|
-
state = nil
|
130
|
-
|
131
|
-
reactor.async do |task|
|
132
|
-
state = :started
|
133
|
-
task.yield
|
134
|
-
state = :finished
|
135
|
-
end
|
136
|
-
|
137
|
-
reactor.run
|
138
|
-
|
139
|
-
expect(state).to be == :finished
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
describe '#stop' do
|
144
|
-
it "can be stopped" do
|
145
|
-
state = nil
|
146
|
-
|
147
|
-
task = reactor.async do |task|
|
148
|
-
state = :started
|
149
|
-
task.sleep(10)
|
150
|
-
state = :finished
|
151
|
-
end
|
152
|
-
|
153
|
-
task.stop
|
154
|
-
|
155
|
-
expect(state).to be == :started
|
156
|
-
expect(task).to be_stopped
|
157
|
-
end
|
158
|
-
|
159
|
-
it "can stop nested tasks with exception handling" do
|
160
|
-
task = reactor.async do |task|
|
161
|
-
child = task.async do |subtask|
|
162
|
-
subtask.sleep(1)
|
163
|
-
end
|
164
|
-
|
165
|
-
begin
|
166
|
-
child.wait
|
167
|
-
ensure
|
168
|
-
child.stop
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
subtask = task.children.first
|
173
|
-
task.stop
|
174
|
-
|
175
|
-
expect(task.status).to be :stopped
|
176
|
-
expect(subtask.status).to be :stopped
|
177
|
-
end
|
178
|
-
|
179
|
-
it "can stop current task" do
|
180
|
-
state = nil
|
181
|
-
|
182
|
-
task = reactor.async do |task|
|
183
|
-
state = :started
|
184
|
-
task.stop
|
185
|
-
state = :finished
|
186
|
-
end
|
187
|
-
|
188
|
-
expect(state).to be == :started
|
189
|
-
expect(task).to be_stopped
|
190
|
-
end
|
191
|
-
|
192
|
-
it "can stop current task using exception" do
|
193
|
-
state = nil
|
194
|
-
|
195
|
-
task = reactor.async do |task|
|
196
|
-
state = :started
|
197
|
-
raise Async::Stop, "I'm finished."
|
198
|
-
state = :finished
|
199
|
-
end
|
200
|
-
|
201
|
-
expect(state).to be == :started
|
202
|
-
expect(task).to be_stopped
|
203
|
-
end
|
204
|
-
|
205
|
-
it "should stop direct child" do
|
206
|
-
parent_task = child_task = nil
|
207
|
-
|
208
|
-
reactor.async do |task|
|
209
|
-
parent_task = task
|
210
|
-
reactor.async do |task|
|
211
|
-
child_task = task
|
212
|
-
task.sleep(10)
|
213
|
-
end
|
214
|
-
task.sleep(10)
|
215
|
-
end
|
216
|
-
|
217
|
-
expect(parent_task).to_not be_nil
|
218
|
-
expect(child_task).to_not be_nil
|
219
|
-
|
220
|
-
expect(parent_task.fiber).to be_alive
|
221
|
-
expect(child_task.fiber).to be_alive
|
222
|
-
|
223
|
-
parent_task.stop
|
224
|
-
|
225
|
-
expect(parent_task).to_not be_alive
|
226
|
-
expect(child_task).to_not be_alive
|
227
|
-
end
|
228
|
-
|
229
|
-
it "can stop nested parent" do
|
230
|
-
parent_task = nil
|
231
|
-
children_tasks = []
|
232
|
-
|
233
|
-
reactor.async do |task|
|
234
|
-
parent_task = task
|
235
|
-
|
236
|
-
reactor.async do |task|
|
237
|
-
children_tasks << task
|
238
|
-
task.sleep(2)
|
239
|
-
end
|
240
|
-
|
241
|
-
reactor.async do |task|
|
242
|
-
children_tasks << task
|
243
|
-
task.sleep(1)
|
244
|
-
parent_task.stop
|
245
|
-
end
|
246
|
-
|
247
|
-
reactor.async do |task|
|
248
|
-
children_tasks << task
|
249
|
-
task.sleep(2)
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
reactor.run
|
254
|
-
|
255
|
-
expect(parent_task).to_not be_alive
|
256
|
-
end
|
257
|
-
|
258
|
-
it "should not remove running task" do
|
259
|
-
top_task = middle_task = bottom_task = nil
|
260
|
-
|
261
|
-
top_task = reactor.async do |task|
|
262
|
-
middle_task = reactor.async do |task|
|
263
|
-
bottom_task = reactor.async do |task|
|
264
|
-
task.sleep(10)
|
265
|
-
end
|
266
|
-
task.sleep(10)
|
267
|
-
end
|
268
|
-
task.sleep(10)
|
269
|
-
end
|
270
|
-
|
271
|
-
bottom_task.stop
|
272
|
-
expect(top_task.children).to include(middle_task)
|
273
|
-
end
|
274
|
-
|
275
|
-
it "can stop resumed task" do
|
276
|
-
items = [1, 2, 3]
|
277
|
-
|
278
|
-
Async do
|
279
|
-
condition = Async::Condition.new
|
280
|
-
|
281
|
-
producer = Async do |subtask|
|
282
|
-
while item = items.pop
|
283
|
-
subtask.yield # (1) Fiber.yield, (3) Reactor -> producer.resume
|
284
|
-
condition.signal(item) # (4) consumer.resume(value)
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
288
|
-
value = condition.wait # (2) value = Fiber.yield
|
289
|
-
expect(value).to be == 3
|
290
|
-
producer.stop # (5) [producer is resumed already] producer.stop
|
291
|
-
end
|
292
|
-
|
293
|
-
expect(items).to be == [1]
|
294
|
-
end
|
295
|
-
end
|
296
|
-
|
297
|
-
describe '#sleep' do
|
298
|
-
let(:duration) {0.01}
|
299
|
-
|
300
|
-
it "can sleep for the requested duration" do
|
301
|
-
state = nil
|
302
|
-
|
303
|
-
reactor.async do |task|
|
304
|
-
task.sleep(duration)
|
305
|
-
state = :finished
|
306
|
-
end
|
307
|
-
|
308
|
-
time = Async::Clock.measure do
|
309
|
-
reactor.run
|
310
|
-
end
|
311
|
-
|
312
|
-
# This is too unstable on travis.
|
313
|
-
# expect(time).to be_within(50).percent_of(duration)
|
314
|
-
expect(time).to be >= duration
|
315
|
-
expect(state).to be == :finished
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
describe '#with_timeout' do
|
320
|
-
it "can extend timeout" do
|
321
|
-
reactor.async do |task|
|
322
|
-
task.with_timeout(0.2) do |timer|
|
323
|
-
task.sleep(0.1)
|
324
|
-
|
325
|
-
expect(timer.fires_in).to be_within(10 * Q).percent_of(0.1)
|
326
|
-
|
327
|
-
timer.reset
|
328
|
-
|
329
|
-
expect(timer.fires_in).to be_within(10 * Q).percent_of(0.2)
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
reactor.run
|
334
|
-
end
|
335
|
-
|
336
|
-
it "will timeout if execution takes too long" do
|
337
|
-
state = nil
|
338
|
-
|
339
|
-
reactor.async do |task|
|
340
|
-
begin
|
341
|
-
task.with_timeout(0.01) do
|
342
|
-
state = :started
|
343
|
-
task.sleep(10)
|
344
|
-
state = :finished
|
345
|
-
end
|
346
|
-
rescue Async::TimeoutError
|
347
|
-
state = :timeout
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
|
-
reactor.run
|
352
|
-
|
353
|
-
expect(state).to be == :timeout
|
354
|
-
end
|
355
|
-
|
356
|
-
it "won't timeout if execution completes in time" do
|
357
|
-
state = nil
|
358
|
-
|
359
|
-
reactor.async do |task|
|
360
|
-
state = :started
|
361
|
-
task.with_timeout(0.01) do
|
362
|
-
task.sleep(0.001)
|
363
|
-
state = :finished
|
364
|
-
end
|
365
|
-
end
|
366
|
-
|
367
|
-
reactor.run
|
368
|
-
|
369
|
-
expect(state).to be == :finished
|
370
|
-
end
|
371
|
-
|
372
|
-
def sleep_forever
|
373
|
-
while true
|
374
|
-
Async::Task.current.sleep(1)
|
375
|
-
end
|
376
|
-
end
|
377
|
-
|
378
|
-
it "contains useful backtrace" do
|
379
|
-
task = Async do |task|
|
380
|
-
task.with_timeout(1.0) do
|
381
|
-
sleep_forever
|
382
|
-
end
|
383
|
-
end
|
384
|
-
|
385
|
-
expect{task.wait}.to raise_error(Async::TimeoutError)
|
386
|
-
|
387
|
-
# TODO replace this with task.result
|
388
|
-
task.wait rescue error = $!
|
389
|
-
expect(error.backtrace).to include(/sleep_forever/)
|
390
|
-
end
|
391
|
-
end
|
392
|
-
|
393
|
-
describe '#wait' do
|
394
|
-
it "will wait on another task to complete" do
|
395
|
-
apples_task = reactor.async do |task|
|
396
|
-
task.sleep(0.1)
|
397
|
-
|
398
|
-
:apples
|
399
|
-
end
|
400
|
-
|
401
|
-
oranges_task = reactor.async do |task|
|
402
|
-
task.sleep(0.01)
|
403
|
-
|
404
|
-
:oranges
|
405
|
-
end
|
406
|
-
|
407
|
-
fruit_salad = reactor.async do |task|
|
408
|
-
[apples_task.wait, oranges_task.wait]
|
409
|
-
end
|
410
|
-
|
411
|
-
reactor.run
|
412
|
-
|
413
|
-
expect(fruit_salad.wait).to be == [:apples, :oranges]
|
414
|
-
end
|
415
|
-
|
416
|
-
it "will raise exceptions when checking result" do
|
417
|
-
error_task = nil
|
418
|
-
|
419
|
-
error_task = reactor.async do |task|
|
420
|
-
raise RuntimeError, "brain not provided"
|
421
|
-
end
|
422
|
-
|
423
|
-
expect do
|
424
|
-
error_task.wait
|
425
|
-
end.to raise_exception(RuntimeError, /brain/)
|
426
|
-
end
|
427
|
-
|
428
|
-
it "will propagate exceptions after async operation" do
|
429
|
-
error_task = nil
|
430
|
-
|
431
|
-
error_task = reactor.async do |task|
|
432
|
-
task.sleep(0.1)
|
433
|
-
|
434
|
-
raise "boom"
|
435
|
-
end
|
436
|
-
|
437
|
-
innocent_task = reactor.async do |task|
|
438
|
-
expect{error_task.wait}.to raise_exception RuntimeError, /boom/
|
439
|
-
end
|
440
|
-
|
441
|
-
expect do
|
442
|
-
reactor.run
|
443
|
-
end.to_not raise_exception
|
444
|
-
|
445
|
-
expect(error_task).to be_finished
|
446
|
-
expect(innocent_task).to be_finished
|
447
|
-
end
|
448
|
-
end
|
449
|
-
|
450
|
-
describe '#children' do
|
451
|
-
it "enumerates children in same order they are created" do
|
452
|
-
tasks = 10.times.map do |i|
|
453
|
-
reactor.async(annotation: "Task #{i}") {|task| task.sleep(1)}
|
454
|
-
end
|
455
|
-
|
456
|
-
expect(reactor.children.each.to_a).to be == tasks
|
457
|
-
end
|
458
|
-
end
|
459
|
-
|
460
|
-
describe '#to_s' do
|
461
|
-
it "should show running" do
|
462
|
-
apples_task = reactor.async do |task|
|
463
|
-
task.sleep(0.1)
|
464
|
-
end
|
465
|
-
|
466
|
-
expect(apples_task.to_s).to include "running"
|
467
|
-
end
|
468
|
-
|
469
|
-
it "should show complete" do
|
470
|
-
apples_task = reactor.async do |task|
|
471
|
-
end
|
472
|
-
|
473
|
-
expect(apples_task.to_s).to include "complete"
|
474
|
-
end
|
475
|
-
end
|
476
|
-
end
|