async 1.25.0 → 1.26.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/lib/async/barrier.rb +1 -1
  3. data/lib/async/node.rb +171 -49
  4. data/lib/async/queue.rb +5 -1
  5. data/lib/async/reactor.rb +16 -11
  6. data/lib/async/version.rb +1 -1
  7. metadata +54 -99
  8. data/.editorconfig +0 -6
  9. data/.github/workflows/development.yml +0 -55
  10. data/.gitignore +0 -14
  11. data/.rspec +0 -3
  12. data/.yardopts +0 -1
  13. data/Gemfile +0 -20
  14. data/Guardfile +0 -14
  15. data/README.md +0 -385
  16. data/Rakefile +0 -40
  17. data/async.gemspec +0 -34
  18. data/bake.rb +0 -33
  19. data/benchmark/async_vs_lightio.rb +0 -84
  20. data/benchmark/fiber_count.rb +0 -10
  21. data/benchmark/rubies/README.md +0 -51
  22. data/benchmark/rubies/benchmark.rb +0 -220
  23. data/benchmark/thread_count.rb +0 -9
  24. data/benchmark/thread_vs_fiber.rb +0 -45
  25. data/examples/async_method.rb +0 -60
  26. data/examples/callback/loop.rb +0 -44
  27. data/examples/capture/README.md +0 -59
  28. data/examples/capture/capture.rb +0 -116
  29. data/examples/fibers.rb +0 -178
  30. data/examples/queue/producer.rb +0 -28
  31. data/examples/sleep_sort.rb +0 -40
  32. data/examples/stop/condition.rb +0 -31
  33. data/examples/stop/sleep.rb +0 -42
  34. data/gems/event.gemfile +0 -4
  35. data/logo.png +0 -0
  36. data/logo.svg +0 -64
  37. data/papers/1982 Grossman.pdf +0 -0
  38. data/papers/1987 ODell.pdf +0 -0
  39. data/spec/async/barrier_spec.rb +0 -116
  40. data/spec/async/chainable_async_examples.rb +0 -13
  41. data/spec/async/clock_spec.rb +0 -37
  42. data/spec/async/condition_examples.rb +0 -105
  43. data/spec/async/condition_spec.rb +0 -72
  44. data/spec/async/logger_spec.rb +0 -65
  45. data/spec/async/node_spec.rb +0 -175
  46. data/spec/async/notification_spec.rb +0 -66
  47. data/spec/async/performance_spec.rb +0 -72
  48. data/spec/async/queue_spec.rb +0 -129
  49. data/spec/async/reactor/nested_spec.rb +0 -52
  50. data/spec/async/reactor_spec.rb +0 -233
  51. data/spec/async/semaphore_spec.rb +0 -169
  52. data/spec/async/task_spec.rb +0 -466
  53. data/spec/async/wrapper_spec.rb +0 -203
  54. data/spec/async_spec.rb +0 -33
  55. data/spec/enumerator_spec.rb +0 -83
  56. data/spec/kernel/async_spec.rb +0 -33
  57. data/spec/kernel/sync_spec.rb +0 -54
  58. data/spec/spec_helper.rb +0 -18
@@ -1,129 +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 semaphore' do
57
- let(:capacity) {2}
58
- let(:semaphore) {Async::Semaphore.new(capacity)}
59
- let(:repeats) {capacity * 2}
60
-
61
- it 'should process several items limited by a semaphore' do
62
- count = 0
63
-
64
- Async do
65
- repeats.times do
66
- subject.enqueue :item
67
- end
68
-
69
- subject.enqueue nil
70
- end
71
-
72
- subject.async(parent: semaphore) do |task|
73
- count += 1
74
- end
75
-
76
- expect(count).to be == repeats
77
- end
78
- end
79
-
80
- it_behaves_like 'chainable async' do
81
- before do
82
- subject.enqueue(:item)
83
-
84
- # The limited queue may block.
85
- Async do
86
- subject.enqueue(nil)
87
- end
88
- end
89
- end
90
- end
91
-
92
- RSpec.describe Async::Queue do
93
- include_context Async::RSpec::Reactor
94
-
95
- it_behaves_like Async::Queue
96
- end
97
-
98
- RSpec.describe Async::LimitedQueue do
99
- include_context Async::RSpec::Reactor
100
-
101
- it_behaves_like Async::Queue
102
-
103
- it 'should become limited' do
104
- expect(subject).to_not be_limited
105
- subject.enqueue(10)
106
- expect(subject).to be_limited
107
- end
108
-
109
- it 'should resume waiting tasks in order' do
110
- total_resumed = 0
111
- total_dequeued = 0
112
- Async do |producer|
113
- 10.times do
114
- producer.async do
115
- subject.enqueue('foo')
116
- total_resumed += 1
117
- end
118
- end
119
- end
120
- Async do |consumer|
121
- 10.times do
122
- subject.dequeue
123
- total_dequeued += 1
124
-
125
- expect(total_resumed).to be == total_dequeued
126
- end
127
- end
128
- end
129
- 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
@@ -1,233 +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 '#stop' do
84
- it "can stop the reactor" do
85
- state = nil
86
-
87
- subject.async do |task|
88
- state = :started
89
- task.sleep(10)
90
- state = :stopped
91
- end
92
-
93
- subject.async do |task|
94
- task.sleep(0.1)
95
- task.reactor.stop
96
- end
97
-
98
- subject.run
99
-
100
- expect(state).to be == :started
101
-
102
- subject.close
103
- end
104
-
105
- it "can stop reactor from different thread" do
106
- events = Thread::Queue.new
107
-
108
- thread = Thread.new do
109
- if events.pop
110
- subject.stop
111
- end
112
- end
113
-
114
- subject.async do |task|
115
- events << true
116
- end
117
-
118
- subject.run
119
-
120
- thread.join
121
-
122
- expect(subject).to be_stopped
123
- end
124
- end
125
-
126
- it "can't return" do
127
- expect do
128
- Async do |task|
129
- return
130
- end.wait
131
- end.to raise_exception(LocalJumpError)
132
- end
133
-
134
- it "is closed after running" do
135
- reactor = nil
136
-
137
- Async do |task|
138
- reactor = task.reactor
139
- end
140
-
141
- expect(reactor).to be_closed
142
-
143
- expect{reactor.run}.to raise_exception(RuntimeError, /closed/)
144
- end
145
-
146
- it "should return a task" do
147
- result = Async do |task|
148
- end
149
-
150
- expect(result).to be_kind_of(Async::Task)
151
- end
152
-
153
- describe '#async' do
154
- include_context Async::RSpec::Reactor
155
-
156
- it "can pass in arguments" do
157
- reactor.async(:arg) do |task, arg|
158
- expect(arg).to be == :arg
159
- end.wait
160
- end
161
-
162
- it "passes in the correct number of arguments" do
163
- reactor.async(:arg1, :arg2, :arg3) do |task, arg1, arg2, arg3|
164
- expect(arg1).to be == :arg1
165
- expect(arg2).to be == :arg2
166
- expect(arg3).to be == :arg3
167
- end.wait
168
- end
169
- end
170
-
171
- describe '#with_timeout' do
172
- let(:duration) {1}
173
-
174
- it "stops immediately" do
175
- start_time = Time.now
176
-
177
- described_class.run do |task|
178
- condition = Async::Condition.new
179
-
180
- task.with_timeout(duration) do
181
- task.async do
182
- condition.wait
183
- end
184
-
185
- condition.signal
186
-
187
- task.yield
188
-
189
- task.children.each(&:wait)
190
- end
191
- end
192
-
193
- duration = Time.now - start_time
194
-
195
- expect(duration).to be < 0.1
196
- end
197
-
198
- let(:timeout_class) {Class.new(RuntimeError)}
199
-
200
- it "raises specified exception" do
201
- expect do
202
- described_class.run do |task|
203
- task.with_timeout(0.0, timeout_class) do
204
- task.sleep(1.0)
205
- end
206
- end.wait
207
- end.to raise_exception(timeout_class)
208
- end
209
-
210
- it "should be fast to use timeouts" do
211
- Benchmark.ips do |x|
212
- x.report('Reactor#with_timeout') do |repeats|
213
- Async do |task|
214
- reactor = task.reactor
215
-
216
- repeats.times do
217
- reactor.with_timeout(1) do
218
- end
219
- end
220
- end
221
- end
222
-
223
- x.compare!
224
- end
225
- end
226
- end
227
-
228
- describe '#to_s' do
229
- it "shows stopped=" do
230
- expect(subject.to_s).to include "stopped"
231
- end
232
- end
233
- 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