async 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d60db4d677d9cb4ed92f654f19ca17a4dab336002ba44290a80545b1f25e9154
4
- data.tar.gz: 9e84c874ef477cd0de6a86022c87a3fe92ae9276ddd3c4f4ccfd9d6600be0672
3
+ metadata.gz: '0496bec665a4c9cb59cc9f52e0f75e8c122ff66b2daddaa0aa6e83022e5e8928'
4
+ data.tar.gz: 2e0c3995dc1de72fee48942eecf96b14fa08f8e0d78083fba96be455a0ffdeab
5
5
  SHA512:
6
- metadata.gz: 7dd4367c1abb5cc79bf635a34b5819522e7f8363c385f69c995fe23d6fd4d7f6fc6a07784c789afbad0ff1ff6726d6d11899dd9b0a87ae582e9f78711c0ab346
7
- data.tar.gz: 0cbef57bb4896a06b11a95f318ad8a0d87435b70f591abc73bb8c7bf76773a341aba47399ef59a813f3d87f32f57112d070081db8598d4d58967f13ac26b4c61
6
+ metadata.gz: cac34c61bf2bde2775d0abbf4185fdecc07f6540ba18017c90ce38ef6d72d95397e09c65b8d9f25f8e3a1ead9635180b38d6666525c00384810c796c6c92d629
7
+ data.tar.gz: 39778867ad4784cf5f44d164f2d97f52d2cc43b869f267242ef5d9d588f626cc656bb01d7f935a8237f9f83ff50bf9b1371032f50ffb5bc39a1af80e2be89adc
checksums.yaml.gz.sig CHANGED
Binary file
data/lib/async/barrier.md CHANGED
@@ -7,6 +7,7 @@ require 'async'
7
7
  require 'async/barrier'
8
8
 
9
9
  Sync do
10
+ Console.logger.info("Barrier Example: sleep sort.")
10
11
  barrier = Async::Barrier.new
11
12
 
12
13
  # Generate an array of 10 numbers:
@@ -31,6 +32,7 @@ end
31
32
  ### Output
32
33
 
33
34
  ~~~
34
- 0.0s info: Sorted
35
- | [0, 0, 0, 0, 1, 2, 2, 3, 6, 6]
35
+ 0.0s info: Barrier Example: sleep sort.
36
+ 9.0s info: Sorted
37
+ | [3, 3, 3, 4, 4, 5, 5, 5, 8, 9]
36
38
  ~~~
data/lib/async/list.rb CHANGED
@@ -15,11 +15,27 @@ module Async
15
15
 
16
16
  # Print a short summary of the list.
17
17
  def to_s
18
- "#<#{self.class.name} size=#{@size}>"
18
+ sprintf("#<%s:0x%x size=%d>", self.class.name, object_id, @size)
19
19
  end
20
20
 
21
21
  alias inspect to_s
22
22
 
23
+ # Fast, safe, unbounded accumulation of children.
24
+ def to_a
25
+ items = []
26
+ current = self
27
+
28
+ while current.tail != self
29
+ unless current.tail.is_a?(Iterator)
30
+ items << current.tail
31
+ end
32
+
33
+ current = current.tail
34
+ end
35
+
36
+ return items
37
+ end
38
+
23
39
  # Points at the end of the list.
24
40
  attr_accessor :head
25
41
 
@@ -118,30 +134,46 @@ module Async
118
134
 
119
135
  # @returns [Boolean] Returns true if the list is empty.
120
136
  def empty?
121
- @tail.equal?(self)
137
+ @size == 0
122
138
  end
123
139
 
140
+ # def validate!(node = nil)
141
+ # previous = self
142
+ # current = @tail
143
+ # found = node.equal?(self)
144
+
145
+ # while true
146
+ # break if current.equal?(self)
147
+
148
+ # if current.head != previous
149
+ # raise "Invalid previous linked list node!"
150
+ # end
151
+
152
+ # if current.is_a?(List) and !current.equal?(self)
153
+ # raise "Invalid list in list node!"
154
+ # end
155
+
156
+ # if node
157
+ # found ||= current.equal?(node)
158
+ # end
159
+
160
+ # previous = current
161
+ # current = current.tail
162
+ # end
163
+
164
+ # if node and !found
165
+ # raise "Node not found in list!"
166
+ # end
167
+ # end
168
+
124
169
  # Iterate over each node in the linked list. It is generally safe to remove the current node, any previous node or any future node during iteration.
125
170
  #
126
171
  # @yields {|node| ...} Yields each node in the list.
127
172
  # @returns [List] Returns self.
128
- def each
173
+ def each(&block)
129
174
  return to_enum unless block_given?
130
175
 
131
- current = self
132
-
133
- while true
134
- node = current.tail
135
- # binding.irb if node.nil? && !node.equal?(self)
136
- break if node.equal?(self)
137
-
138
- yield node
139
-
140
- # If the node has deleted itself or any subsequent node, it will no longer be the next node, so don't use it for continued traversal:
141
- if current.tail.equal?(node)
142
- current = node
143
- end
144
- end
176
+ Iterator.each(self, &block)
145
177
 
146
178
  return self
147
179
  end
@@ -160,22 +192,117 @@ module Async
160
192
 
161
193
  # @returns [Node] Returns the first node in the list, if it is not empty.
162
194
  def first
163
- unless @tail.equal?(self)
164
- @tail
195
+ # validate!
196
+
197
+ current = @tail
198
+
199
+ while !current.equal?(self)
200
+ if current.is_a?(Iterator)
201
+ current = current.tail
202
+ else
203
+ return current
204
+ end
165
205
  end
206
+
207
+ return nil
166
208
  end
167
209
 
168
210
  # @returns [Node] Returns the last node in the list, if it is not empty.
169
211
  def last
170
- unless @head.equal?(self)
171
- @head
212
+ # validate!
213
+
214
+ current = @head
215
+
216
+ while !current.equal?(self)
217
+ if current.is_a?(Iterator)
218
+ current = current.head
219
+ else
220
+ return current
221
+ end
172
222
  end
223
+
224
+ return nil
173
225
  end
174
- end
175
-
176
- # A linked list Node.
177
- class List::Node
178
- attr_accessor :head
179
- attr_accessor :tail
226
+
227
+ def shift
228
+ if node = first
229
+ remove!(node)
230
+ end
231
+ end
232
+
233
+ # A linked list Node.
234
+ class Node
235
+ attr_accessor :head
236
+ attr_accessor :tail
237
+
238
+ alias inspect to_s
239
+ end
240
+
241
+ class Iterator < Node
242
+ def initialize(list)
243
+ @list = list
244
+
245
+ # Insert the iterator as the first item in the list:
246
+ @tail = list.tail
247
+ @tail.head = self
248
+ list.tail = self
249
+ @head = list
250
+ end
251
+
252
+ def remove!
253
+ @head.tail = @tail
254
+ @tail.head = @head
255
+ @head = nil
256
+ @tail = nil
257
+ @list = nil
258
+ end
259
+
260
+ def move_next
261
+ # Move to the next item (which could be an iterator or the end):
262
+ @tail.head = @head
263
+ @head.tail = @tail
264
+ @head = @tail
265
+ @tail = @tail.tail
266
+ @head.tail = self
267
+ @tail.head = self
268
+ end
269
+
270
+ def move_current
271
+ while true
272
+ # Are we at the end of the list?
273
+ if @tail.equal?(@list)
274
+ return nil
275
+ end
276
+
277
+ if @tail.is_a?(Iterator)
278
+ move_next
279
+ else
280
+ return @tail
281
+ end
282
+ end
283
+ end
284
+
285
+ def each
286
+ while current = move_current
287
+ yield current
288
+
289
+ if current.equal?(@tail)
290
+ move_next
291
+ end
292
+ end
293
+ end
294
+
295
+ def self.each(list, &block)
296
+ return if list.empty?
297
+
298
+ iterator = Iterator.new(list)
299
+
300
+ iterator.each(&block)
301
+ ensure
302
+ iterator&.remove!
303
+ end
304
+ end
305
+
306
+ private_constant :Iterator
180
307
  end
181
308
  end
data/lib/async/node.rb CHANGED
@@ -187,13 +187,12 @@ module Async
187
187
  if parent = @parent and finished?
188
188
  parent.remove_child(self)
189
189
 
190
+ # If we have children, then we need to move them to our the parent if they are not finished:
190
191
  if @children
191
- @children.each do |child|
192
+ while child = @children.shift
192
193
  if child.finished?
193
- remove_child(child)
194
+ child.set_parent(nil)
194
195
  else
195
- # In theory we don't need to do this... because we are throwing away the list. However, if you don't correctly update the list when moving the child to the parent, it foobars the enumeration, and subsequent nodes will be skipped, or in the worst case you might start enumerating the parents nodes.
196
- remove_child(child)
197
196
  parent.add_child(child)
198
197
  end
199
198
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2018-2022, by Samuel Williams.
4
+ # Copyright, 2018-2023, by Samuel Williams.
5
5
 
6
6
  require_relative 'list'
7
7
 
@@ -28,6 +28,25 @@ module Async
28
28
  # The tasks waiting on this semaphore.
29
29
  attr :waiting
30
30
 
31
+ # Allow setting the limit. This is useful for cases where the semaphore is used to limit the number of concurrent tasks, but the number of tasks is not known in advance or needs to be modified.
32
+ #
33
+ # On increasing the limit, some tasks may be immediately resumed. On decreasing the limit, some tasks may execute until the count is < than the limit.
34
+ #
35
+ # @parameter limit [Integer] The new limit.
36
+ def limit= limit
37
+ difference = limit - @limit
38
+ @limit = limit
39
+
40
+ # We can't suspend
41
+ if difference > 0
42
+ difference.times do
43
+ break unless node = @waiting.first
44
+
45
+ node.resume
46
+ end
47
+ end
48
+ end
49
+
31
50
  # Is the semaphore currently acquired?
32
51
  def empty?
33
52
  @count.zero?
data/lib/async/task.rb CHANGED
@@ -263,7 +263,7 @@ module Async
263
263
  self.root.resume(@fiber)
264
264
  end
265
265
 
266
- # Finish the current task, and all bound bound IO objects.
266
+ # Finish the current task, moving any children to the parent.
267
267
  def finish!
268
268
  # Allow the fiber to be recycled.
269
269
  @fiber = nil
data/lib/async/version.rb CHANGED
@@ -4,5 +4,5 @@
4
4
  # Copyright, 2017-2022, by Samuel Williams.
5
5
 
6
6
  module Async
7
- VERSION = "2.3.0"
7
+ VERSION = "2.4.0"
8
8
  end
data/license.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright, 2017-2022, by Samuel Williams.
3
+ Copyright, 2017-2023, by Samuel Williams.
4
4
  Copyright, 2017, by Kent Gruber.
5
5
  Copyright, 2017, by Devin Christensen.
6
6
  Copyright, 2018, by Sokolov Yura.
@@ -17,6 +17,9 @@ Copyright, 2020, by Jun Jiang.
17
17
  Copyright, 2020-2022, by Bruno Sutic.
18
18
  Copyright, 2021, by Julien Portalier.
19
19
  Copyright, 2022, by Shannon Skipper.
20
+ Copyright, 2022, by Masafumi Okura.
21
+ Copyright, 2022, by Trevor Turk.
22
+ Copyright, 2022, by Masayuki Yamamoto.
20
23
 
21
24
  Permission is hereby granted, free of charge, to any person obtaining a copy
22
25
  of this software and associated documentation files (the "Software"), to deal
data/readme.md CHANGED
@@ -42,27 +42,3 @@ We welcome contributions to this project.
42
42
  - [falcon](https://github.com/socketry/falcon) — A rack compatible server built on top of `async-http`.
43
43
  - [rubydns](https://github.com/ioquatix/rubydns) — An easy to use Ruby DNS server.
44
44
  - [slack-ruby-bot](https://github.com/slack-ruby/slack-ruby-bot) — A client for making slack bots.
45
-
46
- ## License
47
-
48
- Released under the MIT license.
49
-
50
- Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com).
51
-
52
- Permission is hereby granted, free of charge, to any person obtaining a copy
53
- of this software and associated documentation files (the "Software"), to deal
54
- in the Software without restriction, including without limitation the rights
55
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
56
- copies of the Software, and to permit persons to whom the Software is
57
- furnished to do so, subject to the following conditions:
58
-
59
- The above copyright notice and this permission notice shall be included in
60
- all copies or substantial portions of the Software.
61
-
62
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
63
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
64
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
65
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
66
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
67
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
68
- THE SOFTWARE.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,27 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  - Bruno Sutic
9
- - Devin Christensen
10
9
  - Jeremy Jung
10
+ - Devin Christensen
11
11
  - Kent Gruber
12
- - jeremyjung
13
12
  - Brian Morearty
14
13
  - Jiang Jinyang
15
14
  - Julien Portalier
15
+ - Jun Jiang
16
+ - Ken Muryoi
17
+ - Masafumi Okura
18
+ - Masayuki Yamamoto
16
19
  - Olle Jonsson
17
20
  - Patrik Wenger
18
21
  - Ryan Musgrave
19
22
  - Salim Semaoune
20
23
  - Shannon Skipper
21
- - Sokolov Yura aka funny_falcon
24
+ - Sokolov Yura
22
25
  - Stefan Wrobel
23
- - jasl
24
- - muryoimpl
26
+ - Trevor Turk
25
27
  autorequire:
26
28
  bindir: bin
27
29
  cert_chain:
@@ -54,7 +56,7 @@ cert_chain:
54
56
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
55
57
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
56
58
  -----END CERTIFICATE-----
57
- date: 2022-12-04 00:00:00.000000000 Z
59
+ date: 2023-03-01 00:00:00.000000000 Z
58
60
  dependencies:
59
61
  - !ruby/object:Gem::Dependency
60
62
  name: console
@@ -259,7 +261,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
259
261
  - !ruby/object:Gem::Version
260
262
  version: '0'
261
263
  requirements: []
262
- rubygems_version: 3.3.7
264
+ rubygems_version: 3.4.7
263
265
  signing_key:
264
266
  specification_version: 4
265
267
  summary: A concurrency framework for Ruby.
metadata.gz.sig CHANGED
Binary file