async 1.26.1 → 1.28.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/lib/async/barrier.rb +1 -1
  3. data/lib/async/clock.rb +33 -1
  4. data/lib/async/logger.rb +1 -6
  5. data/lib/async/node.rb +20 -2
  6. data/lib/async/queue.rb +4 -0
  7. data/lib/async/reactor.rb +69 -8
  8. data/lib/async/scheduler.rb +112 -0
  9. data/lib/async/task.rb +11 -3
  10. data/lib/async/version.rb +1 -1
  11. metadata +46 -104
  12. data/.editorconfig +0 -6
  13. data/.github/workflows/development.yml +0 -55
  14. data/.gitignore +0 -14
  15. data/.rspec +0 -3
  16. data/.yardopts +0 -1
  17. data/Gemfile +0 -20
  18. data/Guardfile +0 -14
  19. data/README.md +0 -385
  20. data/Rakefile +0 -40
  21. data/async.gemspec +0 -34
  22. data/bake.rb +0 -33
  23. data/benchmark/async_vs_lightio.rb +0 -84
  24. data/benchmark/fiber_count.rb +0 -10
  25. data/benchmark/rubies/README.md +0 -51
  26. data/benchmark/rubies/benchmark.rb +0 -220
  27. data/benchmark/thread_count.rb +0 -9
  28. data/benchmark/thread_vs_fiber.rb +0 -45
  29. data/examples/async_method.rb +0 -60
  30. data/examples/callback/loop.rb +0 -44
  31. data/examples/capture/README.md +0 -59
  32. data/examples/capture/capture.rb +0 -116
  33. data/examples/fibers.rb +0 -178
  34. data/examples/queue/producer.rb +0 -28
  35. data/examples/sleep_sort.rb +0 -40
  36. data/examples/stop/condition.rb +0 -31
  37. data/examples/stop/sleep.rb +0 -42
  38. data/gems/event.gemfile +0 -4
  39. data/logo.png +0 -0
  40. data/logo.svg +0 -64
  41. data/papers/1982 Grossman.pdf +0 -0
  42. data/papers/1987 ODell.pdf +0 -0
  43. data/spec/async/barrier_spec.rb +0 -116
  44. data/spec/async/chainable_async_examples.rb +0 -13
  45. data/spec/async/clock_spec.rb +0 -37
  46. data/spec/async/condition_examples.rb +0 -105
  47. data/spec/async/condition_spec.rb +0 -72
  48. data/spec/async/logger_spec.rb +0 -65
  49. data/spec/async/node_spec.rb +0 -193
  50. data/spec/async/notification_spec.rb +0 -66
  51. data/spec/async/performance_spec.rb +0 -72
  52. data/spec/async/queue_spec.rb +0 -133
  53. data/spec/async/reactor/nested_spec.rb +0 -52
  54. data/spec/async/reactor_spec.rb +0 -253
  55. data/spec/async/semaphore_spec.rb +0 -169
  56. data/spec/async/task_spec.rb +0 -476
  57. data/spec/async/wrapper_spec.rb +0 -203
  58. data/spec/async_spec.rb +0 -33
  59. data/spec/enumerator_spec.rb +0 -83
  60. data/spec/kernel/async_spec.rb +0 -39
  61. data/spec/kernel/sync_spec.rb +0 -54
  62. data/spec/spec_helper.rb +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af5004e8d05722b3187b65bad44d03c64514cef04b3ea84f604f2491b04c9441
4
- data.tar.gz: 3e00948623889a9a584767a5678b55d474b4015603da9031eea4ab420bea80e0
3
+ metadata.gz: a043ccb6378ff70b23eff7218723e910af5828508241e4ca87bb59669eee5990
4
+ data.tar.gz: c1891f280b416fd092caa8e54473697856718d55a820dc784ad3026ba301c4b7
5
5
  SHA512:
6
- metadata.gz: eb57c398f8f778ded45849d98412106133bd68294eeee34e734144b1792b63c1c7f4da9087cf36ed14d385efacd730a4e461f029ba22503a89efa56debd7dc5c
7
- data.tar.gz: d81812db0ca0f6ad8d81d6582ce82d6b1e210b437a6614d825ad0bc1be4cb200f2f3c930df51f6fc963b82e0c98bfc757fe339646a9227d6dacfab06e70b469e
6
+ metadata.gz: 61abcad6fc07e331c6eaba134865e329964b7c8c87f23338e4f8ce39dd250fa2c9719e83eb74a55c284ada13873f5ad996ba68162c131be2a933b67a124d17ed
7
+ data.tar.gz: b5039970211fec3361ee6bf8044be988771a968a7f43ca8f20d3a4eea95234fc45fbc78f395b8ff2a9cb77407865915102ca38936b57c875fa1b07848050cae3
@@ -23,7 +23,7 @@
23
23
  require_relative 'task'
24
24
 
25
25
  module Async
26
- # A semaphore is used to control access to a common resource in a concurrent system. A useful way to think of a semaphore as used in the real-world systems is as a record of how many units of a particular resource are available, coupled with operations to adjust that record safely (i.e. to avoid race conditions) as units are required or become free, and, if necessary, wait until a unit of the resource becomes available.
26
+ # A barrier is used to synchronize multiple tasks, waiting for them all to complete before continuing.
27
27
  class Barrier
28
28
  def initialize(parent: nil)
29
29
  @tasks = []
@@ -21,7 +21,7 @@
21
21
  # THE SOFTWARE.
22
22
 
23
23
  module Async
24
- module Clock
24
+ class Clock
25
25
  # Get the current elapsed monotonic time.
26
26
  def self.now
27
27
  ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
@@ -35,5 +35,37 @@ module Async
35
35
 
36
36
  return self.now - start_time
37
37
  end
38
+
39
+ def self.start
40
+ self.new.tap(&:start!)
41
+ end
42
+
43
+ def initialize(total = 0)
44
+ @total = total
45
+ @started = nil
46
+ end
47
+
48
+ def start!
49
+ @started ||= Clock.now
50
+ end
51
+
52
+ def stop!
53
+ if @started
54
+ @total += (Clock.now - @started)
55
+ @started = nil
56
+ end
57
+
58
+ return @total
59
+ end
60
+
61
+ def total
62
+ total = @total
63
+
64
+ if @started
65
+ total += (Clock.now - @started)
66
+ end
67
+
68
+ return total
69
+ end
38
70
  end
39
71
  end
@@ -24,10 +24,5 @@ require 'console'
24
24
  require_relative 'task'
25
25
 
26
26
  module Async
27
- # @return the current logger, either the active tasks logger, or the global event console logger.
28
- def self.logger
29
- if task = Task.current?
30
- task.logger
31
- end || Console.logger
32
- end
27
+ extend Console
33
28
  end
@@ -217,6 +217,10 @@ module Async
217
217
  end
218
218
  end
219
219
 
220
+ def backtrace(*arguments)
221
+ nil
222
+ end
223
+
220
224
  def to_s
221
225
  "\#<#{description}>"
222
226
  end
@@ -297,9 +301,23 @@ module Async
297
301
  @children&.each(&:stop)
298
302
  end
299
303
 
300
- def print_hierarchy(out = $stdout)
304
+ def print_hierarchy(out = $stdout, backtrace: true)
301
305
  self.traverse do |node, level|
302
- out.puts "#{"\t" * level}#{node}"
306
+ indent = "\t" * level
307
+
308
+ out.puts "#{indent}#{node}"
309
+
310
+ print_backtrace(out, indent, node) if backtrace
311
+ end
312
+ end
313
+
314
+ private
315
+
316
+ def print_backtrace(out, indent, node)
317
+ if backtrace = node.backtrace
318
+ backtrace.each_with_index do |line, index|
319
+ out.puts "#{indent}#{index.zero? ? "→ " : " "}#{line}"
320
+ end
303
321
  end
304
322
  end
305
323
  end
@@ -34,6 +34,10 @@ module Async
34
34
 
35
35
  attr :items
36
36
 
37
+ def size
38
+ @items.size
39
+ end
40
+
37
41
  def empty?
38
42
  @items.empty?
39
43
  end
@@ -23,6 +23,7 @@
23
23
  require_relative 'logger'
24
24
  require_relative 'task'
25
25
  require_relative 'wrapper'
26
+ require_relative 'scheduler'
26
27
 
27
28
  require 'nio'
28
29
  require 'timers'
@@ -82,12 +83,60 @@ module Async
82
83
  @ready = []
83
84
  @running = []
84
85
 
86
+ if Scheduler.supported?
87
+ @scheduler = Scheduler.new(self)
88
+ else
89
+ @scheduler = nil
90
+ end
91
+
85
92
  @interrupted = false
86
93
  @guard = Mutex.new
94
+ @blocked = 0
95
+ @unblocked = []
96
+ end
97
+
98
+ attr :scheduler
99
+
100
+ # @reentrant Not thread safe.
101
+ def block(blocker, timeout)
102
+ fiber = Fiber.current
103
+
104
+ if timeout
105
+ timer = self.after(timeout) do
106
+ if fiber.alive?
107
+ fiber.resume(false)
108
+ end
109
+ end
110
+ end
111
+
112
+ begin
113
+ @blocked += 1
114
+ Fiber.yield
115
+ ensure
116
+ @blocked -= 1
117
+ end
118
+ ensure
119
+ timer&.cancel
120
+ end
121
+
122
+ # @reentrant Thread safe.
123
+ def unblock(blocker, fiber)
124
+ @guard.synchronize do
125
+ @unblocked << fiber
126
+ @selector.wakeup
127
+ end
128
+ end
129
+
130
+ def fiber(&block)
131
+ if @scheduler
132
+ Fiber.new(blocking: false, &block)
133
+ else
134
+ Fiber.new(&block)
135
+ end
87
136
  end
88
137
 
89
138
  def logger
90
- @logger ||= Console.logger
139
+ @logger || Console.logger
91
140
  end
92
141
 
93
142
  def to_s
@@ -98,9 +147,6 @@ module Async
98
147
  @children.nil?
99
148
  end
100
149
 
101
- # TODO Remove these in next major release. They are too confusing to use correctly.
102
- def_delegators :@timers, :every, :after
103
-
104
150
  # Start an asynchronous task within the specified reactor. The task will be
105
151
  # executed until the first blocking call, at which point it will yield and
106
152
  # and this method will return.
@@ -157,7 +203,7 @@ module Async
157
203
 
158
204
  def finished?
159
205
  # TODO I'm not sure if checking `@running.empty?` is really required.
160
- super && @ready.empty? && @running.empty?
206
+ super && @ready.empty? && @running.empty? && @blocked.zero?
161
207
  end
162
208
 
163
209
  # Run one iteration of the event loop.
@@ -177,6 +223,18 @@ module Async
177
223
  @running.clear
178
224
  end
179
225
 
226
+ unless @blocked.zero?
227
+ unblocked = Array.new
228
+
229
+ @guard.synchronize do
230
+ unblocked, @unblocked = @unblocked, unblocked
231
+ end
232
+
233
+ while fiber = unblocked.pop
234
+ fiber.resume if fiber.alive?
235
+ end
236
+ end
237
+
180
238
  if @ready.empty?
181
239
  interval = @timers.wait_interval
182
240
  else
@@ -200,7 +258,7 @@ module Async
200
258
  interval = timeout
201
259
  end
202
260
 
203
- # logger.debug(self) {"Selecting with #{@children&.size} children with interval = #{interval ? interval.round(2) : 'infinite'}..."}
261
+ # logger.info(self) {"Selecting with #{@children&.size} children with interval = #{interval ? interval.round(2) : 'infinite'}..."}
204
262
  if monitors = @selector.select(interval)
205
263
  monitors.each do |monitor|
206
264
  monitor.value.resume
@@ -226,6 +284,8 @@ module Async
226
284
  def run(*arguments, **options, &block)
227
285
  raise RuntimeError, 'Reactor has been closed' if @selector.nil?
228
286
 
287
+ @scheduler&.set!
288
+
229
289
  initial_task = self.async(*arguments, **options, &block) if block_given?
230
290
 
231
291
  while self.run_once
@@ -234,6 +294,7 @@ module Async
234
294
 
235
295
  return initial_task
236
296
  ensure
297
+ @scheduler&.clear!
237
298
  logger.debug(self) {"Exiting run-loop because #{$! ? $! : 'finished'}."}
238
299
  end
239
300
 
@@ -266,7 +327,7 @@ module Async
266
327
  def sleep(duration)
267
328
  fiber = Fiber.current
268
329
 
269
- timer = self.after(duration) do
330
+ timer = @timers.after(duration) do
270
331
  if fiber.alive?
271
332
  fiber.resume
272
333
  end
@@ -283,7 +344,7 @@ module Async
283
344
  def with_timeout(timeout, exception = TimeoutError)
284
345
  fiber = Fiber.current
285
346
 
286
- timer = self.after(timeout) do
347
+ timer = @timers.after(timeout) do
287
348
  if fiber.alive?
288
349
  error = exception.new("execution expired")
289
350
  fiber.resume error
@@ -0,0 +1,112 @@
1
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'clock'
22
+
23
+ module Async
24
+ class Scheduler
25
+ if Fiber.respond_to?(:set_scheduler)
26
+ def self.supported?
27
+ true
28
+ end
29
+ else
30
+ def self.supported?
31
+ false
32
+ end
33
+ end
34
+
35
+ def initialize(reactor)
36
+ @reactor = reactor
37
+ @wrappers = nil
38
+ end
39
+
40
+ def set!
41
+ @wrappers = {}
42
+ Fiber.set_scheduler(self)
43
+ end
44
+
45
+ def clear!
46
+ # Because these instances are created with `autoclose: false`, this does not close the underlying file descriptor:
47
+ # @ios&.each_value(&:close)
48
+
49
+ @wrappers = nil
50
+ Fiber.set_scheduler(nil)
51
+ end
52
+
53
+ private def from_io(io)
54
+ @wrappers[io] ||= Wrapper.new(io, @reactor)
55
+ end
56
+
57
+ def io_wait(io, events, timeout = nil)
58
+ wrapper = from_io(io)
59
+
60
+ if events == ::IO::READABLE
61
+ if wrapper.wait_readable(timeout)
62
+ return ::IO::READABLE
63
+ end
64
+ elsif events == ::IO::WRITABLE
65
+ if wrapper.wait_writable(timeout)
66
+ return ::IO::WRITABLE
67
+ end
68
+ else
69
+ if wrapper.wait_any(timeout)
70
+ return events
71
+ end
72
+ end
73
+
74
+ return false
75
+ ensure
76
+ wrapper.reactor = nil
77
+ end
78
+
79
+ # Wait for the specified process ID to exit.
80
+ # @parameter pid [Integer] The process ID to wait for.
81
+ # @parameter flags [Integer] A bit-mask of flags suitable for `Process::Status.wait`.
82
+ # @returns [Process::Status] A process status instance.
83
+ def process_wait(pid, flags)
84
+ Thread.new do
85
+ Process::Status.wait(pid, flags)
86
+ end.value
87
+ end
88
+
89
+ def kernel_sleep(duration)
90
+ @reactor.sleep(duration)
91
+ end
92
+
93
+ def block(blocker, timeout)
94
+ @reactor.block(blocker, timeout)
95
+ end
96
+
97
+ def unblock(blocker, fiber)
98
+ @reactor.unblock(blocker, fiber)
99
+ end
100
+
101
+ def close
102
+ end
103
+
104
+ def fiber(&block)
105
+ task = Task.new(&block)
106
+
107
+ task.resume
108
+
109
+ return task.fiber
110
+ end
111
+ end
112
+ end
@@ -86,17 +86,24 @@ module Async
86
86
  @fiber = make_fiber(&block)
87
87
  end
88
88
 
89
+ if Fiber.current.respond_to?(:backtrace)
90
+ def backtrace(*arguments)
91
+ @fiber&.backtrace(*arguments)
92
+ end
93
+ end
94
+
89
95
  def to_s
90
96
  "\#<#{self.description} (#{@status})>"
91
97
  end
92
98
 
93
99
  def logger
94
- @logger ||= @parent&.logger
100
+ @logger || Console.logger
95
101
  end
96
102
 
97
103
  # @attr ios [Reactor] The reactor the task was created within.
98
104
  attr :reactor
99
- def_delegators :@reactor, :with_timeout, :timeout, :sleep
105
+
106
+ def_delegators :@reactor, :with_timeout, :sleep
100
107
 
101
108
  # Yield back to the reactor and allow other fibers to execute.
102
109
  def yield
@@ -226,7 +233,7 @@ module Async
226
233
  private
227
234
 
228
235
  # This is a very tricky aspect of tasks to get right. I've modelled it after `Thread` but it's slightly different in that the exception can propagate back up through the reactor. If the user writes code which raises an exception, that exception should always be visible, i.e. cause a failure. If it's not visible, such code fails silently and can be very difficult to debug.
229
- # As an explcit choice, the user can start a task which doesn't propagate exceptions. This only applies to `StandardError` and derived tasks. This allows tasks to internally capture their error state which is raised when invoking `Task#result` similar to how `Thread#join` works. This mode makes `Async::Task` behave more like a promise, and you would need to ensure that someone calls `Task#result` otherwise you might miss important errors.
236
+ # As an explcit choice, the user can start a task which doesn't propagate exceptions. This only applies to `StandardError` and derived tasks. This allows tasks to internally capture their error state which is raised when invoking `Task#result` similar to how `Thread#join` works. This mode makes {ruby Async::Task} behave more like a promise, and you would need to ensure that someone calls `Task#result` otherwise you might miss important errors.
230
237
  def fail!(exception = nil, propagate = true)
231
238
  @status = :failed
232
239
  @result = exception
@@ -289,6 +296,7 @@ module Async
289
296
  def set!
290
297
  # This is actually fiber-local:
291
298
  Thread.current[:async_task] = self
299
+ Console.logger = @logger if @logger
292
300
  end
293
301
  end
294
302
  end
@@ -21,5 +21,5 @@
21
21
  # THE SOFTWARE.
22
22
 
23
23
  module Async
24
- VERSION = "1.26.1"
24
+ VERSION = "1.28.2"
25
25
  end
metadata CHANGED
@@ -1,57 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.26.1
4
+ version: 1.28.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-14 00:00:00.000000000 Z
11
+ date: 2020-12-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: nio4r
14
+ name: console
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.3'
19
+ version: '1.10'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.3'
26
+ version: '1.10'
27
27
  - !ruby/object:Gem::Dependency
28
- name: timers
28
+ name: nio4r
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '4.1'
33
+ version: '2.3'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '4.1'
40
+ version: '2.3'
41
41
  - !ruby/object:Gem::Dependency
42
- name: console
42
+ name: timers
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.0'
47
+ version: '4.1'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.0'
54
+ version: '4.1'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: async-rspec
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -67,19 +67,33 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.1'
69
69
  - !ruby/object:Gem::Dependency
70
- name: covered
70
+ name: bake
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '0.10'
75
+ version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '0.10'
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: benchmark-ips
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: bundler
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -95,68 +109,39 @@ dependencies:
95
109
  - !ruby/object:Gem::Version
96
110
  version: '0'
97
111
  - !ruby/object:Gem::Dependency
98
- name: rspec
112
+ name: covered
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
115
  - - "~>"
102
116
  - !ruby/object:Gem::Version
103
- version: '3.6'
117
+ version: '0.10'
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
- version: '3.6'
124
+ version: '0.10'
111
125
  - !ruby/object:Gem::Dependency
112
- name: bake-bundler
126
+ name: rspec
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
- - - ">="
129
+ - - "~>"
116
130
  - !ruby/object:Gem::Version
117
- version: '0'
131
+ version: '3.6'
118
132
  type: :development
119
133
  prerelease: false
120
134
  version_requirements: !ruby/object:Gem::Requirement
121
135
  requirements:
122
- - - ">="
136
+ - - "~>"
123
137
  - !ruby/object:Gem::Version
124
- version: '0'
125
- description: "\t\tAsync is a modern concurrency framework for Ruby. It implements
126
- the\n\t\treactor pattern, providing both non-blocking I/O and timer events.\n"
138
+ version: '3.6'
139
+ description:
127
140
  email:
128
- - samuel.williams@oriontransfer.co.nz
129
141
  executables: []
130
142
  extensions: []
131
143
  extra_rdoc_files: []
132
144
  files:
133
- - ".editorconfig"
134
- - ".github/workflows/development.yml"
135
- - ".gitignore"
136
- - ".rspec"
137
- - ".yardopts"
138
- - Gemfile
139
- - Guardfile
140
- - README.md
141
- - Rakefile
142
- - async.gemspec
143
- - bake.rb
144
- - benchmark/async_vs_lightio.rb
145
- - benchmark/fiber_count.rb
146
- - benchmark/rubies/README.md
147
- - benchmark/rubies/benchmark.rb
148
- - benchmark/thread_count.rb
149
- - benchmark/thread_vs_fiber.rb
150
- - examples/async_method.rb
151
- - examples/callback/loop.rb
152
- - examples/capture/README.md
153
- - examples/capture/capture.rb
154
- - examples/fibers.rb
155
- - examples/queue/producer.rb
156
- - examples/sleep_sort.rb
157
- - examples/stop/condition.rb
158
- - examples/stop/sleep.rb
159
- - gems/event.gemfile
160
145
  - lib/async.rb
161
146
  - lib/async/barrier.rb
162
147
  - lib/async/clock.rb
@@ -168,41 +153,18 @@ files:
168
153
  - lib/async/notification.rb
169
154
  - lib/async/queue.rb
170
155
  - lib/async/reactor.rb
156
+ - lib/async/scheduler.rb
171
157
  - lib/async/semaphore.rb
172
158
  - lib/async/task.rb
173
159
  - lib/async/version.rb
174
160
  - lib/async/wrapper.rb
175
161
  - lib/kernel/async.rb
176
162
  - lib/kernel/sync.rb
177
- - logo.png
178
- - logo.svg
179
- - papers/1982 Grossman.pdf
180
- - papers/1987 ODell.pdf
181
- - spec/async/barrier_spec.rb
182
- - spec/async/chainable_async_examples.rb
183
- - spec/async/clock_spec.rb
184
- - spec/async/condition_examples.rb
185
- - spec/async/condition_spec.rb
186
- - spec/async/logger_spec.rb
187
- - spec/async/node_spec.rb
188
- - spec/async/notification_spec.rb
189
- - spec/async/performance_spec.rb
190
- - spec/async/queue_spec.rb
191
- - spec/async/reactor/nested_spec.rb
192
- - spec/async/reactor_spec.rb
193
- - spec/async/semaphore_spec.rb
194
- - spec/async/task_spec.rb
195
- - spec/async/wrapper_spec.rb
196
- - spec/async_spec.rb
197
- - spec/enumerator_spec.rb
198
- - spec/kernel/async_spec.rb
199
- - spec/kernel/sync_spec.rb
200
- - spec/spec_helper.rb
201
163
  homepage: https://github.com/socketry/async
202
164
  licenses:
203
165
  - MIT
204
166
  metadata: {}
205
- post_install_message:
167
+ post_install_message:
206
168
  rdoc_options: []
207
169
  require_paths:
208
170
  - lib
@@ -217,28 +179,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
179
  - !ruby/object:Gem::Version
218
180
  version: '0'
219
181
  requirements: []
220
- rubygems_version: 3.1.2
221
- signing_key:
182
+ rubygems_version: 3.2.3
183
+ signing_key:
222
184
  specification_version: 4
223
- summary: Async is a concurrency framework for Ruby.
224
- test_files:
225
- - spec/async/barrier_spec.rb
226
- - spec/async/chainable_async_examples.rb
227
- - spec/async/clock_spec.rb
228
- - spec/async/condition_examples.rb
229
- - spec/async/condition_spec.rb
230
- - spec/async/logger_spec.rb
231
- - spec/async/node_spec.rb
232
- - spec/async/notification_spec.rb
233
- - spec/async/performance_spec.rb
234
- - spec/async/queue_spec.rb
235
- - spec/async/reactor/nested_spec.rb
236
- - spec/async/reactor_spec.rb
237
- - spec/async/semaphore_spec.rb
238
- - spec/async/task_spec.rb
239
- - spec/async/wrapper_spec.rb
240
- - spec/async_spec.rb
241
- - spec/enumerator_spec.rb
242
- - spec/kernel/async_spec.rb
243
- - spec/kernel/sync_spec.rb
244
- - spec/spec_helper.rb
185
+ summary: A concurrency framework for Ruby.
186
+ test_files: []