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/queue_spec.rb
DELETED
@@ -1,133 +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/queue'
|
25
|
-
require 'async/rspec'
|
26
|
-
require 'async/semaphore'
|
27
|
-
|
28
|
-
require_relative 'condition_examples'
|
29
|
-
require_relative 'chainable_async_examples'
|
30
|
-
|
31
|
-
RSpec.shared_context Async::Queue do
|
32
|
-
it 'should process items in order' do
|
33
|
-
reactor.async do |task|
|
34
|
-
10.times do |i|
|
35
|
-
task.sleep(0.001)
|
36
|
-
subject.enqueue(i)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
10.times do |j|
|
41
|
-
expect(subject.dequeue).to be == j
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'can dequeue items asynchronously' do
|
46
|
-
reactor.async do |task|
|
47
|
-
subject << 1
|
48
|
-
subject << nil
|
49
|
-
end
|
50
|
-
|
51
|
-
subject.async do |task, item|
|
52
|
-
expect(item).to be 1
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
context 'with an empty queue' do
|
57
|
-
it {is_expected.to be_empty}
|
58
|
-
end
|
59
|
-
|
60
|
-
context 'with semaphore' do
|
61
|
-
let(:capacity) {2}
|
62
|
-
let(:semaphore) {Async::Semaphore.new(capacity)}
|
63
|
-
let(:repeats) {capacity * 2}
|
64
|
-
|
65
|
-
it 'should process several items limited by a semaphore' do
|
66
|
-
count = 0
|
67
|
-
|
68
|
-
Async do
|
69
|
-
repeats.times do
|
70
|
-
subject.enqueue :item
|
71
|
-
end
|
72
|
-
|
73
|
-
subject.enqueue nil
|
74
|
-
end
|
75
|
-
|
76
|
-
subject.async(parent: semaphore) do |task|
|
77
|
-
count += 1
|
78
|
-
end
|
79
|
-
|
80
|
-
expect(count).to be == repeats
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
it_behaves_like 'chainable async' do
|
85
|
-
before do
|
86
|
-
subject.enqueue(:item)
|
87
|
-
|
88
|
-
# The limited queue may block.
|
89
|
-
Async do
|
90
|
-
subject.enqueue(nil)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
RSpec.describe Async::Queue do
|
97
|
-
include_context Async::RSpec::Reactor
|
98
|
-
|
99
|
-
it_behaves_like Async::Queue
|
100
|
-
end
|
101
|
-
|
102
|
-
RSpec.describe Async::LimitedQueue do
|
103
|
-
include_context Async::RSpec::Reactor
|
104
|
-
|
105
|
-
it_behaves_like Async::Queue
|
106
|
-
|
107
|
-
it 'should become limited' do
|
108
|
-
expect(subject).to_not be_limited
|
109
|
-
subject.enqueue(10)
|
110
|
-
expect(subject).to be_limited
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'should resume waiting tasks in order' do
|
114
|
-
total_resumed = 0
|
115
|
-
total_dequeued = 0
|
116
|
-
|
117
|
-
Async do |producer|
|
118
|
-
10.times do
|
119
|
-
producer.async do
|
120
|
-
subject.enqueue('foo')
|
121
|
-
total_resumed += 1
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
10.times do
|
127
|
-
item = subject.dequeue
|
128
|
-
total_dequeued += 1
|
129
|
-
|
130
|
-
expect(total_resumed).to be == total_dequeued
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
@@ -1,52 +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
|
-
RSpec.describe Async::Reactor do
|
24
|
-
describe '::run (in existing reactor)' do
|
25
|
-
include_context Async::RSpec::Reactor
|
26
|
-
|
27
|
-
it "should nest reactor" do
|
28
|
-
outer_reactor = Async::Task.current.reactor
|
29
|
-
inner_reactor = nil
|
30
|
-
|
31
|
-
described_class.run do |task|
|
32
|
-
inner_reactor = task.reactor
|
33
|
-
end
|
34
|
-
|
35
|
-
expect(outer_reactor).to be_kind_of(described_class)
|
36
|
-
expect(outer_reactor).to be_eql(inner_reactor)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
describe '::run' do
|
41
|
-
it "should nest reactor" do
|
42
|
-
expect(Async::Task.current?).to be_nil
|
43
|
-
inner_reactor = nil
|
44
|
-
|
45
|
-
described_class.run do |task|
|
46
|
-
inner_reactor = task.reactor
|
47
|
-
end
|
48
|
-
|
49
|
-
expect(inner_reactor).to be_kind_of(described_class)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
data/spec/async/reactor_spec.rb
DELETED
@@ -1,253 +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/rspec/reactor'
|
25
|
-
|
26
|
-
require 'benchmark/ips'
|
27
|
-
|
28
|
-
RSpec.describe Async::Reactor do
|
29
|
-
describe '#run' do
|
30
|
-
it "can run tasks on different fibers" do
|
31
|
-
outer_fiber = Fiber.current
|
32
|
-
inner_fiber = nil
|
33
|
-
|
34
|
-
described_class.run do |task|
|
35
|
-
task.sleep(0)
|
36
|
-
inner_fiber = Fiber.current
|
37
|
-
end
|
38
|
-
|
39
|
-
expect(inner_fiber).to_not be nil
|
40
|
-
expect(outer_fiber).to_not be == inner_fiber
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe '#close' do
|
45
|
-
it "can close empty reactor" do
|
46
|
-
subject.close
|
47
|
-
|
48
|
-
expect(subject).to be_closed
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
describe '#run_once' do
|
53
|
-
it "can run the reactor" do
|
54
|
-
# Run the reactor for 1 second:
|
55
|
-
task = subject.async do |task|
|
56
|
-
task.yield
|
57
|
-
end
|
58
|
-
|
59
|
-
expect(task).to be_running
|
60
|
-
|
61
|
-
# This will resume the task, and then the reactor will be finished.
|
62
|
-
expect(subject.run_once).to be false
|
63
|
-
|
64
|
-
expect(task).to be_finished
|
65
|
-
end
|
66
|
-
|
67
|
-
it "can run one iteration" do
|
68
|
-
state = nil
|
69
|
-
|
70
|
-
subject.async do |task|
|
71
|
-
state = :started
|
72
|
-
task.yield
|
73
|
-
state = :finished
|
74
|
-
end
|
75
|
-
|
76
|
-
expect(state).to be :started
|
77
|
-
|
78
|
-
subject.run_once
|
79
|
-
expect(state).to be :finished
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
describe '#print_hierarchy' do
|
84
|
-
it "can print hierarchy" do
|
85
|
-
subject.async do |parent|
|
86
|
-
parent.async do |child|
|
87
|
-
child.sleep 1
|
88
|
-
end
|
89
|
-
|
90
|
-
parent.sleep 1
|
91
|
-
end
|
92
|
-
|
93
|
-
output = StringIO.new
|
94
|
-
subject.print_hierarchy(output)
|
95
|
-
lines = output.string.lines
|
96
|
-
|
97
|
-
expect(lines[0]).to be =~ /#<Async::Reactor.*(running)/
|
98
|
-
expect(lines[1]).to be =~ /\t#<Async::Task.*(running)/
|
99
|
-
expect(lines[2]).to be =~ /\t\t#<Async::Task.*(running)/
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
describe '#stop' do
|
104
|
-
it "can stop the reactor" do
|
105
|
-
state = nil
|
106
|
-
|
107
|
-
subject.async(annotation: "sleep(10)") do |task|
|
108
|
-
state = :started
|
109
|
-
task.sleep(10)
|
110
|
-
state = :stopped
|
111
|
-
end
|
112
|
-
|
113
|
-
subject.async(annotation: "reactor.stop") do |task|
|
114
|
-
task.sleep(0.1)
|
115
|
-
task.reactor.stop
|
116
|
-
end
|
117
|
-
|
118
|
-
subject.run
|
119
|
-
|
120
|
-
expect(state).to be == :started
|
121
|
-
|
122
|
-
subject.close
|
123
|
-
end
|
124
|
-
|
125
|
-
it "can stop reactor from different thread" do
|
126
|
-
events = Thread::Queue.new
|
127
|
-
|
128
|
-
thread = Thread.new do
|
129
|
-
if events.pop
|
130
|
-
subject.stop
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
subject.async do |task|
|
135
|
-
events << true
|
136
|
-
end
|
137
|
-
|
138
|
-
subject.run
|
139
|
-
|
140
|
-
thread.join
|
141
|
-
|
142
|
-
expect(subject).to be_stopped
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
it "can't return" do
|
147
|
-
expect do
|
148
|
-
Async do |task|
|
149
|
-
return
|
150
|
-
end.wait
|
151
|
-
end.to raise_exception(LocalJumpError)
|
152
|
-
end
|
153
|
-
|
154
|
-
it "is closed after running" do
|
155
|
-
reactor = nil
|
156
|
-
|
157
|
-
Async do |task|
|
158
|
-
reactor = task.reactor
|
159
|
-
end
|
160
|
-
|
161
|
-
expect(reactor).to be_closed
|
162
|
-
|
163
|
-
expect{reactor.run}.to raise_exception(RuntimeError, /closed/)
|
164
|
-
end
|
165
|
-
|
166
|
-
it "should return a task" do
|
167
|
-
result = Async do |task|
|
168
|
-
end
|
169
|
-
|
170
|
-
expect(result).to be_kind_of(Async::Task)
|
171
|
-
end
|
172
|
-
|
173
|
-
describe '#async' do
|
174
|
-
include_context Async::RSpec::Reactor
|
175
|
-
|
176
|
-
it "can pass in arguments" do
|
177
|
-
reactor.async(:arg) do |task, arg|
|
178
|
-
expect(arg).to be == :arg
|
179
|
-
end.wait
|
180
|
-
end
|
181
|
-
|
182
|
-
it "passes in the correct number of arguments" do
|
183
|
-
reactor.async(:arg1, :arg2, :arg3) do |task, arg1, arg2, arg3|
|
184
|
-
expect(arg1).to be == :arg1
|
185
|
-
expect(arg2).to be == :arg2
|
186
|
-
expect(arg3).to be == :arg3
|
187
|
-
end.wait
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
describe '#with_timeout' do
|
192
|
-
let(:duration) {1}
|
193
|
-
|
194
|
-
it "stops immediately" do
|
195
|
-
start_time = Time.now
|
196
|
-
|
197
|
-
described_class.run do |task|
|
198
|
-
condition = Async::Condition.new
|
199
|
-
|
200
|
-
task.with_timeout(duration) do
|
201
|
-
task.async do
|
202
|
-
condition.wait
|
203
|
-
end
|
204
|
-
|
205
|
-
condition.signal
|
206
|
-
|
207
|
-
task.yield
|
208
|
-
|
209
|
-
task.children.each(&:wait)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
duration = Time.now - start_time
|
214
|
-
|
215
|
-
expect(duration).to be < 0.1
|
216
|
-
end
|
217
|
-
|
218
|
-
let(:timeout_class) {Class.new(RuntimeError)}
|
219
|
-
|
220
|
-
it "raises specified exception" do
|
221
|
-
expect do
|
222
|
-
described_class.run do |task|
|
223
|
-
task.with_timeout(0.0, timeout_class) do
|
224
|
-
task.sleep(1.0)
|
225
|
-
end
|
226
|
-
end.wait
|
227
|
-
end.to raise_exception(timeout_class)
|
228
|
-
end
|
229
|
-
|
230
|
-
it "should be fast to use timeouts" do
|
231
|
-
Benchmark.ips do |x|
|
232
|
-
x.report('Reactor#with_timeout') do |repeats|
|
233
|
-
Async do |task|
|
234
|
-
reactor = task.reactor
|
235
|
-
|
236
|
-
repeats.times do
|
237
|
-
reactor.with_timeout(1) do
|
238
|
-
end
|
239
|
-
end
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
x.compare!
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
describe '#to_s' do
|
249
|
-
it "shows stopped=" do
|
250
|
-
expect(subject.to_s).to include "stopped"
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
@@ -1,169 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright, 2018, 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/semaphore'
|
24
|
-
require 'async/barrier'
|
25
|
-
require 'async/rspec'
|
26
|
-
|
27
|
-
require_relative 'chainable_async_examples'
|
28
|
-
|
29
|
-
RSpec.describe Async::Semaphore do
|
30
|
-
include_context Async::RSpec::Reactor
|
31
|
-
|
32
|
-
context '#async' do
|
33
|
-
let(:repeats) {40}
|
34
|
-
let(:limit) {4}
|
35
|
-
|
36
|
-
it 'should process work in batches' do
|
37
|
-
semaphore = Async::Semaphore.new(limit)
|
38
|
-
current, maximum = 0, 0
|
39
|
-
|
40
|
-
result = repeats.times.map do |i|
|
41
|
-
semaphore.async do |task|
|
42
|
-
current += 1
|
43
|
-
maximum = [current, maximum].max
|
44
|
-
task.sleep(rand * 0.1)
|
45
|
-
current -= 1
|
46
|
-
|
47
|
-
i
|
48
|
-
end
|
49
|
-
end.collect(&:result)
|
50
|
-
|
51
|
-
# Verify that the maximum number of concurrent tasks was the specificed limit:
|
52
|
-
expect(maximum).to be == limit
|
53
|
-
|
54
|
-
# Verify that the results were in the correct order:
|
55
|
-
expect(result).to be == (0...repeats).to_a
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'only allows one task at a time' do
|
59
|
-
semaphore = Async::Semaphore.new(1)
|
60
|
-
order = []
|
61
|
-
|
62
|
-
3.times.map do |i|
|
63
|
-
semaphore.async do |task|
|
64
|
-
order << i
|
65
|
-
task.sleep(0.1)
|
66
|
-
order << i
|
67
|
-
end
|
68
|
-
end.collect(&:result)
|
69
|
-
|
70
|
-
expect(order).to be == [0, 0, 1, 1, 2, 2]
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'allows tasks to execute concurrently' do
|
74
|
-
semaphore = Async::Semaphore.new(3)
|
75
|
-
order = []
|
76
|
-
|
77
|
-
3.times.map do |i|
|
78
|
-
semaphore.async do |task|
|
79
|
-
order << i
|
80
|
-
task.sleep(0.1)
|
81
|
-
order << i
|
82
|
-
end
|
83
|
-
end.collect(&:result)
|
84
|
-
|
85
|
-
expect(order).to be == [0, 1, 2, 0, 1, 2]
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
context '#waiting' do
|
90
|
-
subject {Async::Semaphore.new(0)}
|
91
|
-
it 'handles exceptions thrown while waiting' do
|
92
|
-
expect do
|
93
|
-
reactor.with_timeout(0.1) do
|
94
|
-
subject.acquire do
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end.to raise_error(Async::TimeoutError)
|
98
|
-
|
99
|
-
expect(subject.waiting).to be_empty
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
context '#count' do
|
104
|
-
it 'should count number of current acquisitions' do
|
105
|
-
expect(subject.count).to be == 0
|
106
|
-
|
107
|
-
subject.acquire do
|
108
|
-
expect(subject.count).to be == 1
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
context '#limit' do
|
114
|
-
it 'should have a default limit' do
|
115
|
-
expect(subject.limit).to be == 1
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
context '#empty?' do
|
120
|
-
it 'should be empty unless acquired' do
|
121
|
-
expect(subject).to be_empty
|
122
|
-
|
123
|
-
subject.acquire do
|
124
|
-
expect(subject).to_not be_empty
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
context '#blocking?' do
|
130
|
-
it 'will be blocking when acquired' do
|
131
|
-
expect(subject).to_not be_blocking
|
132
|
-
|
133
|
-
subject.acquire do
|
134
|
-
expect(subject).to be_blocking
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
context '#acquire/#release' do
|
140
|
-
it 'works when called without block' do
|
141
|
-
subject.acquire
|
142
|
-
|
143
|
-
expect(subject.count).to be == 1
|
144
|
-
|
145
|
-
subject.release
|
146
|
-
|
147
|
-
expect(subject.count).to be == 0
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
context 'with barrier' do
|
152
|
-
let(:capacity) {2}
|
153
|
-
let(:barrier) {Async::Barrier.new}
|
154
|
-
let(:repeats) {capacity * 2}
|
155
|
-
|
156
|
-
it 'should execute several tasks and wait using a barrier' do
|
157
|
-
repeats.times do
|
158
|
-
subject.async(parent: barrier) do |task|
|
159
|
-
task.sleep 0.1
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
expect(barrier.size).to be == repeats
|
164
|
-
barrier.wait
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
it_behaves_like 'chainable async'
|
169
|
-
end
|