async 1.25.1 → 1.27.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) 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 +24 -5
  6. data/lib/async/queue.rb +5 -1
  7. data/lib/async/reactor.rb +7 -10
  8. data/lib/async/task.rb +10 -2
  9. data/lib/async/version.rb +1 -1
  10. metadata +44 -103
  11. data/.editorconfig +0 -6
  12. data/.github/workflows/development.yml +0 -55
  13. data/.gitignore +0 -14
  14. data/.rspec +0 -3
  15. data/.yardopts +0 -1
  16. data/Gemfile +0 -20
  17. data/Guardfile +0 -14
  18. data/README.md +0 -385
  19. data/Rakefile +0 -40
  20. data/async.gemspec +0 -34
  21. data/bake.rb +0 -33
  22. data/benchmark/async_vs_lightio.rb +0 -84
  23. data/benchmark/fiber_count.rb +0 -10
  24. data/benchmark/rubies/README.md +0 -51
  25. data/benchmark/rubies/benchmark.rb +0 -220
  26. data/benchmark/thread_count.rb +0 -9
  27. data/benchmark/thread_vs_fiber.rb +0 -45
  28. data/examples/async_method.rb +0 -60
  29. data/examples/callback/loop.rb +0 -44
  30. data/examples/capture/README.md +0 -59
  31. data/examples/capture/capture.rb +0 -116
  32. data/examples/fibers.rb +0 -178
  33. data/examples/queue/producer.rb +0 -28
  34. data/examples/sleep_sort.rb +0 -40
  35. data/examples/stop/condition.rb +0 -31
  36. data/examples/stop/sleep.rb +0 -42
  37. data/gems/event.gemfile +0 -4
  38. data/logo.png +0 -0
  39. data/logo.svg +0 -64
  40. data/papers/1982 Grossman.pdf +0 -0
  41. data/papers/1987 ODell.pdf +0 -0
  42. data/spec/async/barrier_spec.rb +0 -116
  43. data/spec/async/chainable_async_examples.rb +0 -13
  44. data/spec/async/clock_spec.rb +0 -37
  45. data/spec/async/condition_examples.rb +0 -105
  46. data/spec/async/condition_spec.rb +0 -72
  47. data/spec/async/logger_spec.rb +0 -65
  48. data/spec/async/node_spec.rb +0 -193
  49. data/spec/async/notification_spec.rb +0 -66
  50. data/spec/async/performance_spec.rb +0 -72
  51. data/spec/async/queue_spec.rb +0 -129
  52. data/spec/async/reactor/nested_spec.rb +0 -52
  53. data/spec/async/reactor_spec.rb +0 -253
  54. data/spec/async/semaphore_spec.rb +0 -169
  55. data/spec/async/task_spec.rb +0 -476
  56. data/spec/async/wrapper_spec.rb +0 -203
  57. data/spec/async_spec.rb +0 -33
  58. data/spec/enumerator_spec.rb +0 -83
  59. data/spec/kernel/async_spec.rb +0 -33
  60. data/spec/kernel/sync_spec.rb +0 -54
  61. data/spec/spec_helper.rb +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 70efaa49b29fd36596f22f7796c475610955cc63836725b00775f6c1025aa976
4
- data.tar.gz: d5e7987bcb581c20b3ac17fba0ef803a61f154ec107b55ad01220c16ae2a32e6
3
+ metadata.gz: 1d1048beb05a88fed1922f32624f61bf5ed8b1e70c2bd9b0e0c17bfad60aa359
4
+ data.tar.gz: 0eb19742b401a5ffb95286c766cf68e3159e3b94f57b8fd4272f1038c5dabc00
5
5
  SHA512:
6
- metadata.gz: d47987f2b355ab4dff7e06443787190dc8567abe30391b3a0a2dde55efb4592c14af94b42f52cf2b7f6e35d9868bb1f2cfbdd23cb9abddb4c1ba34a97cf0dab9
7
- data.tar.gz: 014fa5e68d7fb509f6120cbce6e07f75d6c17c86b8d5dcc93278555c4e11ea27a2a8883ba8193359aeed1ab3d5303d92e30b053cf840aa31c0b4f9b002d7c5d4
6
+ metadata.gz: 9c21be88e7a5eea9e6a0380f49eabd47e06522e204b61bb97fc9085053c3e800182a51a83cec001a1bc8533a3f3ff48d1cb1b0987aa15587fbb53ea9209777b6
7
+ data.tar.gz: 79ed71d369b9bda125239835befe60d2842f33e0cd3ed3b6ebadbf996dccf43cc2605b33119ceaf4ac8bb0e602671efb06665660c20e2702f983cb6a8459208c
@@ -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
@@ -72,8 +72,7 @@ module Async
72
72
  end
73
73
 
74
74
  item.head = nil
75
- # Don't do this, because it will break enumeration.
76
- # item.tail = nil
75
+ item.tail = nil
77
76
 
78
77
  @size -= 1
79
78
 
@@ -85,8 +84,10 @@ module Async
85
84
 
86
85
  item = @head
87
86
  while item
87
+ # We store the tail pointer so we can remove the current item from the linked list:
88
+ tail = item.tail
88
89
  yield item
89
- item = item.tail
90
+ item = tail
90
91
  end
91
92
  end
92
93
 
@@ -216,6 +217,10 @@ module Async
216
217
  end
217
218
  end
218
219
 
220
+ def backtrace(*arguments)
221
+ nil
222
+ end
223
+
219
224
  def to_s
220
225
  "\#<#{description}>"
221
226
  end
@@ -296,9 +301,23 @@ module Async
296
301
  @children&.each(&:stop)
297
302
  end
298
303
 
299
- def print_hierarchy(out = $stdout)
304
+ def print_hierarchy(out = $stdout, backtrace: true)
300
305
  self.traverse do |node, level|
301
- 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
302
321
  end
303
322
  end
304
323
  end
@@ -34,7 +34,11 @@ module Async
34
34
 
35
35
  attr :items
36
36
 
37
- def enqueue item
37
+ def empty?
38
+ @items.empty?
39
+ end
40
+
41
+ def enqueue(item)
38
42
  @items.push(item)
39
43
 
40
44
  self.signal unless self.empty?
@@ -50,10 +50,10 @@ module Async
50
50
 
51
51
  return reactor.async(*arguments, **options, &block)
52
52
  else
53
- reactor = self.new(**options)
53
+ reactor = self.new
54
54
 
55
55
  begin
56
- return reactor.run(*arguments, &block)
56
+ return reactor.run(*arguments, **options, &block)
57
57
  ensure
58
58
  reactor.close
59
59
  end
@@ -87,7 +87,7 @@ module Async
87
87
  end
88
88
 
89
89
  def logger
90
- @logger ||= Console.logger
90
+ @logger || Console.logger
91
91
  end
92
92
 
93
93
  def to_s
@@ -98,9 +98,6 @@ module Async
98
98
  @children.nil?
99
99
  end
100
100
 
101
- # TODO Remove these in next major release. They are too confusing to use correctly.
102
- def_delegators :@timers, :every, :after
103
-
104
101
  # Start an asynchronous task within the specified reactor. The task will be
105
102
  # executed until the first blocking call, at which point it will yield and
106
103
  # and this method will return.
@@ -223,10 +220,10 @@ module Async
223
220
  end
224
221
 
225
222
  # Run the reactor until all tasks are finished. Proxies arguments to {#async} immediately before entering the loop, if a block is provided.
226
- def run(*arguments, &block)
223
+ def run(*arguments, **options, &block)
227
224
  raise RuntimeError, 'Reactor has been closed' if @selector.nil?
228
225
 
229
- initial_task = self.async(*arguments, &block) if block_given?
226
+ initial_task = self.async(*arguments, **options, &block) if block_given?
230
227
 
231
228
  while self.run_once
232
229
  # Round and round we go!
@@ -266,7 +263,7 @@ module Async
266
263
  def sleep(duration)
267
264
  fiber = Fiber.current
268
265
 
269
- timer = self.after(duration) do
266
+ timer = @timers.after(duration) do
270
267
  if fiber.alive?
271
268
  fiber.resume
272
269
  end
@@ -283,7 +280,7 @@ module Async
283
280
  def with_timeout(timeout, exception = TimeoutError)
284
281
  fiber = Fiber.current
285
282
 
286
- timer = self.after(timeout) do
283
+ timer = @timers.after(timeout) do
287
284
  if fiber.alive?
288
285
  error = exception.new("execution expired")
289
286
  fiber.resume error
@@ -86,16 +86,23 @@ 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
105
+
99
106
  def_delegators :@reactor, :with_timeout, :timeout, :sleep
100
107
 
101
108
  # Yield back to the reactor and allow other fibers to execute.
@@ -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.25.1"
24
+ VERSION = "1.27.0"
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.25.1
4
+ version: 1.27.0
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-04-25 00:00:00.000000000 Z
11
+ date: 2020-11-13 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
@@ -174,35 +159,11 @@ files:
174
159
  - lib/async/wrapper.rb
175
160
  - lib/kernel/async.rb
176
161
  - 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
162
  homepage: https://github.com/socketry/async
202
163
  licenses:
203
164
  - MIT
204
165
  metadata: {}
205
- post_install_message:
166
+ post_install_message:
206
167
  rdoc_options: []
207
168
  require_paths:
208
169
  - lib
@@ -218,27 +179,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
218
179
  version: '0'
219
180
  requirements: []
220
181
  rubygems_version: 3.1.2
221
- signing_key:
182
+ signing_key:
222
183
  specification_version: 4
223
- summary: Async is an concurrency framework based 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
184
+ summary: A concurrency framework for Ruby.
185
+ test_files: []