async 2.8.2 → 2.9.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 953c51a9b7552058772c90c36cc99d5a6cd26de3c32d3b424bc5929de81a1960
4
- data.tar.gz: 63b115b69ea49ba7192982de38b936fc6d07623aa6139ce51ee2000c949ad759
3
+ metadata.gz: e93ed3ea9094d074f430f9518bf0087f57abf732bf196bed5cf8249315aac33d
4
+ data.tar.gz: 233dffa50c8bb88cd514545280e3bef088b998a1ddb58e6db68d1a7c8a268c32
5
5
  SHA512:
6
- metadata.gz: 3023d786331d88fbb94c36b0ab1597f123e5794d410773b9005dfc6df8212c91d106cbeb8506c1c6725e059ac6e82ed1e77667c595d033eb2ff5ea9d9de681f2
7
- data.tar.gz: 31c4192c27d349f045fa25ba2165948630da063abe5369512def7c54d653961ee5c7d2e82ec36808910a26f81f51c23d6674e1b4993888936410d7649cbd2ec0
6
+ metadata.gz: bede7ace58ac0e5f6bbefd05a89855a3f80ddf3d02a441aaa73b0a64adeb82b83d02d064121ae267b719519a6fc03f86b7b586f8af3901ae12fcfc6db2d5612c
7
+ data.tar.gz: a093ddf356f924089fc8500bee1570cac0e7a4a2e131127eeae0b65813905ae853f44e448f18ecda3d55e39d33f2c7e96c41a34f53cc02259ac8b5bef02e857a
checksums.yaml.gz.sig CHANGED
Binary file
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2024, by Samuel Williams.
5
+
6
+ module Async
7
+ class Idler
8
+ def initialize(maximum_load = 0.8, backoff: 0.01, parent: nil)
9
+ @maximum_load = maximum_load
10
+ @backoff = backoff
11
+ @parent = parent
12
+ end
13
+
14
+ def async(*arguments, parent: (@parent or Task.current), **options, &block)
15
+ wait
16
+
17
+ # It is crucial that we optimistically execute the child task, so that we prevent a tight loop invoking this method from consuming all available resources.
18
+ parent.async(*arguments, **options, &block)
19
+ end
20
+
21
+ def wait
22
+ scheduler = Fiber.scheduler
23
+ backoff = nil
24
+
25
+ while true
26
+ load = scheduler.load
27
+ break if load < @maximum_load
28
+
29
+ if backoff
30
+ sleep(backoff)
31
+ backoff *= 2.0
32
+ else
33
+ scheduler.yield
34
+ backoff = @backoff
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -37,9 +37,33 @@ module Async
37
37
 
38
38
  @blocked = 0
39
39
 
40
+ @busy_time = 0.0
41
+ @idle_time = 0.0
42
+
40
43
  @timers = ::Timers::Group.new
41
44
  end
42
45
 
46
+ # Compute the scheduler load according to the busy and idle times that are updated by the run loop.
47
+ # @returns [Float] The load of the scheduler. 0.0 means no load, 1.0 means fully loaded or over-loaded.
48
+ def load
49
+ total_time = @busy_time + @idle_time
50
+
51
+ # If the total time is zero, then the load is zero:
52
+ return 0.0 if total_time.zero?
53
+
54
+ # We normalize to a 1 second window:
55
+ if total_time > 1.0
56
+ ratio = 1.0 / total_time
57
+ @busy_time *= ratio
58
+ @idle_time *= ratio
59
+
60
+ # We don't need to divide here as we've already normalised it to a 1s window:
61
+ return @busy_time
62
+ else
63
+ return @busy_time / total_time
64
+ end
65
+ end
66
+
43
67
  def scheduler_close
44
68
  # If the execution context (thread) was handling an exception, we want to exit as quickly as possible:
45
69
  unless $!
@@ -267,6 +291,8 @@ module Async
267
291
  # @parameter timeout [Float | Nil] The maximum timeout, or if nil, indefinite.
268
292
  # @returns [Boolean] Whether there is more work to do.
269
293
  private def run_once!(timeout = 0)
294
+ start_time = Async::Clock.now
295
+
270
296
  interval = @timers.wait_interval
271
297
 
272
298
  # If there is no interval to wait (thus no timers), and no tasks, we could be done:
@@ -288,6 +314,15 @@ module Async
288
314
 
289
315
  @timers.fire
290
316
 
317
+ # Compute load:
318
+ end_time = Async::Clock.now
319
+ total_duration = end_time - start_time
320
+ idle_duration = @selector.idle_duration
321
+ busy_duration = total_duration - idle_duration
322
+
323
+ @busy_time += busy_duration
324
+ @idle_time += idle_duration
325
+
291
326
  # The reactor still has work to do:
292
327
  return true
293
328
  end
data/lib/async/task.rb CHANGED
@@ -208,7 +208,7 @@ module Async
208
208
  # @parameter later [Boolean] Whether to stop the task later, or immediately.
209
209
  def stop(later = false)
210
210
  if self.stopped?
211
- # If we already stopped this task... don't try to stop it again:
211
+ # If the task is already stopped, a `stop` state transition re-enters the same state which is a no-op. However, we will also attempt to stop any running children too. This can happen if the children did not stop correctly the first time around. Doing this should probably be considered a bug, but it's better to be safe than sorry.
212
212
  return stopped!
213
213
  end
214
214
 
data/lib/async/version.rb CHANGED
@@ -4,5 +4,5 @@
4
4
  # Copyright, 2017-2024, by Samuel Williams.
5
5
 
6
6
  module Async
7
- VERSION = "2.8.2"
7
+ VERSION = "2.9.0"
8
8
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.2
4
+ version: 2.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -61,7 +61,7 @@ cert_chain:
61
61
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
62
62
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
63
63
  -----END CERTIFICATE-----
64
- date: 2024-02-24 00:00:00.000000000 Z
64
+ date: 2024-03-05 00:00:00.000000000 Z
65
65
  dependencies:
66
66
  - !ruby/object:Gem::Dependency
67
67
  name: console
@@ -97,14 +97,20 @@ dependencies:
97
97
  requirements:
98
98
  - - "~>"
99
99
  - !ruby/object:Gem::Version
100
- version: '1.1'
100
+ version: '1.5'
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 1.5.1
101
104
  type: :runtime
102
105
  prerelease: false
103
106
  version_requirements: !ruby/object:Gem::Requirement
104
107
  requirements:
105
108
  - - "~>"
106
109
  - !ruby/object:Gem::Version
107
- version: '1.1'
110
+ version: '1.5'
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: 1.5.1
108
114
  - !ruby/object:Gem::Dependency
109
115
  name: timers
110
116
  requirement: !ruby/object:Gem::Requirement
@@ -131,6 +137,7 @@ files:
131
137
  - lib/async/clock.rb
132
138
  - lib/async/condition.md
133
139
  - lib/async/condition.rb
140
+ - lib/async/idler.rb
134
141
  - lib/async/list.rb
135
142
  - lib/async/node.rb
136
143
  - lib/async/notification.rb
metadata.gz.sig CHANGED
Binary file