async 1.20.1 → 1.21.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: 54073e0570fc66e2aedec5657883edaf4aa90ed0e93241c9d2210debf8886441
4
- data.tar.gz: 24377adc700b7631969fd299765427ca06208508857eacd5be33b41a137c76c7
3
+ metadata.gz: b9c9a081ed81fc6b4b0b34ebb5282063574994045189a9544b968c7729543cf1
4
+ data.tar.gz: df9d9266a02ff86895cfc9934fbafbeeb7159cb1b964f10705323d9f4798ae34
5
5
  SHA512:
6
- metadata.gz: e6a0f47087e557cfb5d2c9ed32b6fe5738ae1f756b99f23c1ab98bf8722ce22d63cddb629cab9225a98ea901b20912c04e267ac94f194ab913e5a511912bb187
7
- data.tar.gz: fae19fc4eaad3c8ae827bdf54b2ecacf793c31890bbc47088bc7c01af704cde8eb6f98a7b273706898137d4ca368bcecb15823f8b5f151344e6bada5b12c9adf
6
+ metadata.gz: 1f5014904c26006fd50462c9161f3ae24f867ed995569bc1faecebe67d3a1b8799eb4a91896121a07885512ae21361be18f9f9ea3614825140cb3596239cc13b
7
+ data.tar.gz: 26c13f37945ceb4d2542a2ef0736b6fe04cc9515d90053d4b2a00888a5501c008ce614849462b006216a94a1eece3fc781cf378f25f369ae65bceeede12dbfe6
@@ -0,0 +1,4 @@
1
+ # These are supported funding model platforms
2
+
3
+ # github: ioquatix
4
+ custom: https://github.com/socketry/community/#funding
@@ -0,0 +1,9 @@
1
+
2
+ fibers = []
3
+
4
+ (1..).each do |i|
5
+ fibers << Fiber.new{}
6
+ fibers.last.resume
7
+ puts i
8
+ end
9
+
@@ -0,0 +1,8 @@
1
+
2
+ threads = []
3
+
4
+ (1..).each do |i|
5
+ threads << Thread.new{sleep}
6
+ puts i
7
+ end
8
+
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright, 2019, 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 'benchmark/ips'
24
+
25
+ GC.disable
26
+
27
+ Benchmark.ips do |benchmark|
28
+ benchmark.time = 1
29
+ benchmark.warmup = 1
30
+
31
+ benchmark.report("Thread.new{}") do |count|
32
+ while count > 0
33
+ Thread.new{count -= 1}.join
34
+ end
35
+ end
36
+
37
+ benchmark.report("Fiber.new{}") do |count|
38
+ while count > 0
39
+ Fiber.new{count -= 1}.resume
40
+ end
41
+ end
42
+
43
+ benchmark.compare!
44
+ end
@@ -34,10 +34,10 @@ def parse(value)
34
34
  end
35
35
  end
36
36
 
37
- def strace(pid, duration = 10)
37
+ def strace(pid, duration = 60)
38
38
  input, output = IO.pipe
39
39
 
40
- pid = Process.spawn("strace", "-p", pid.to_s, "-cqf", "-w", "-e", "trace=read,write,sendto,recvfrom", err: output)
40
+ pid = Process.spawn("strace", "-p", pid.to_s, "-cqf", "-w", "-e", "!futex", err: output)
41
41
 
42
42
  output.close
43
43
 
@@ -46,15 +46,21 @@ def strace(pid, duration = 10)
46
46
  Signal.trap(:INT, :DEFAULT)
47
47
  end
48
48
 
49
+ Thread.new do
50
+ sleep duration
51
+ Process.kill(:INT, pid)
52
+ end
53
+
49
54
  summary = {}
50
55
 
51
- if line = input.gets
52
- rule = input.gets # horizontal separator
53
- pattern = Regexp.new(
54
- rule.split(/\s/).map{|s| "(.{1,#{s.size}})"}.join(' ')
55
- )
56
-
57
- header = pattern.match(line).captures.map{|key| key.strip.to_sym}
56
+ if first_line = input.gets
57
+ if rule = input.gets # horizontal separator
58
+ pattern = Regexp.new(
59
+ rule.split(/\s/).map{|s| "(.{1,#{s.size}})"}.join(' ')
60
+ )
61
+
62
+ header = pattern.match(first_line).captures.map{|key| key.strip.to_sym}
63
+ end
58
64
 
59
65
  while line = input.gets
60
66
  break if line == rule
@@ -71,7 +77,11 @@ def strace(pid, duration = 10)
71
77
  end
72
78
  end
73
79
 
74
- Process.waitpid(pid)
80
+ _, status = Process.waitpid2(pid)
81
+
82
+ Console.logger.error(status) do |buffer|
83
+ buffer.puts first_line
84
+ end unless status.success?
75
85
 
76
86
  return summary
77
87
  end
@@ -80,6 +90,7 @@ pids.each do |pid|
80
90
  start_times = getrusage(pid)
81
91
  Console.logger.info("Process #{pid} start times:", start_times)
82
92
 
93
+ # sleep 60
83
94
  summary = strace(pid)
84
95
 
85
96
  Console.logger.info("strace -p #{pid}") do |buffer|
@@ -94,7 +105,7 @@ pids.each do |pid|
94
105
  if total = summary[:total]
95
106
  process_duration = end_times.utime - start_times.utime
96
107
  wait_duration = summary[:total][:seconds]
97
-
108
+
98
109
  Console.logger.info("Process Waiting: #{wait_duration.round(4)}s out of #{process_duration.round(4)}s") do |buffer|
99
110
  buffer.puts "Wait percentage: #{(wait_duration / process_duration * 100.0).round(2)}%"
100
111
  end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'async'
4
+ require 'async/queue'
5
+
6
+ Async do
7
+ # Queue of up to 10 items:
8
+ items = Async::LimitedQueue.new(10)
9
+
10
+ # Five producers:
11
+ 5.times do
12
+ Async do |task|
13
+ while true
14
+ t = rand
15
+ task.sleep(t)
16
+ items.enqueue(t)
17
+ end
18
+ end
19
+ end
20
+
21
+ # A single consumer:
22
+ Async do |task|
23
+ while item = items.dequeue
24
+ puts "dequeue -> #{item}"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # require 'async'; require 'async/queue'
4
+
5
+ require_relative '../../lib/async'; require_relative '../../lib/async/queue'
6
+
7
+ Async do |consumer|
8
+ consumer.annotate "consumer"
9
+ condition = Async::Condition.new
10
+
11
+ producer = Async do |subtask|
12
+ subtask.annotate "subtask"
13
+
14
+ (1..).each do |value|
15
+ puts "producer yielding"
16
+ subtask.yield # (1) Fiber.yield, (3) Reactor -> producer.resume
17
+ condition.signal(value) # (4) consumer.resume(value)
18
+ end
19
+
20
+ puts "producer exiting"
21
+ end
22
+
23
+ value = condition.wait # (2) value = Fiber.yield
24
+ puts "producer.stop"
25
+ producer.stop # (5) [producer is resumed already] producer.stop
26
+
27
+ puts "consumer exiting"
28
+ end
29
+
30
+ puts "Done."
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../../lib/async'
4
+
5
+ require 'async/http/endpoint'
6
+ require 'async/http/server'
7
+
8
+ require 'async/http/internet'
9
+
10
+ # To query the web server:
11
+ # curl http://localhost:9292/kittens
12
+
13
+ Async do |parent|
14
+ endpoint = Async::HTTP::Endpoint.parse("http://localhost:9292")
15
+ internet = Async::HTTP::Internet.new
16
+
17
+ server = Async::HTTP::Server.for(endpoint) do |request|
18
+ if request.path =~ /\/(.*)/
19
+ keyword = $1
20
+
21
+ response = internet.get("https://www.google.com/search?q=#{keyword}")
22
+
23
+ count = response.read.scan(keyword).size
24
+
25
+ Protocol::HTTP::Response[200, [], ["Google found #{count} instance(s) of #{keyword}.\n"]]
26
+ else
27
+ Protocol::HTTP::Response[404, [], []]
28
+ end
29
+ end
30
+
31
+ tasks = server.run
32
+
33
+ #while true
34
+ parent.sleep(10)
35
+ parent.reactor.print_hierarchy
36
+ #end
37
+
38
+ parent.stop # -> Async::Stop
39
+
40
+ tasks.each(&:stop)
41
+ end
@@ -22,15 +22,11 @@ require_relative "async/version"
22
22
  require_relative "async/logger"
23
23
  require_relative "async/reactor"
24
24
 
25
+ require_relative "kernel/async"
26
+
25
27
  module Async
26
28
  # Invoke `Reactor.run` with all arguments/block.
27
29
  def self.run(*args, &block)
28
30
  Reactor.run(*args, &block)
29
31
  end
30
- end
31
-
32
- module Kernel
33
- def Async(*args, &block)
34
- Async::Reactor.run(*args, &block)
35
- end
36
- end
32
+ end
@@ -201,7 +201,7 @@ module Async
201
201
  interval = 0
202
202
  end
203
203
 
204
- # logger.debug(self) {"Selecting with #{@children&.count} children with interval = #{interval.inspect}..."}
204
+ # logger.debug(self) {"Selecting with #{@children&.size} children with interval = #{interval.inspect}..."}
205
205
  if monitors = @selector.select(interval)
206
206
  monitors.each do |monitor|
207
207
  monitor.value.resume
@@ -27,13 +27,26 @@ require_relative 'condition'
27
27
  module Async
28
28
  # Raised when a task is explicitly stopped.
29
29
  class Stop < Exception
30
+ class Later
31
+ def initialize(task)
32
+ @task = task
33
+ end
34
+
35
+ def alive?
36
+ true
37
+ end
38
+
39
+ def resume
40
+ @task.stop
41
+ end
42
+ end
30
43
  end
31
44
 
32
45
  # A task represents the state associated with the execution of an asynchronous
33
46
  # block.
34
47
  class Task < Node
35
48
  extend Forwardable
36
-
49
+
37
50
  # Yield the unerlying `result` for the task. If the result
38
51
  # is an Exception, then that result will be raised an its
39
52
  # exception.
@@ -85,7 +98,7 @@ module Async
85
98
 
86
99
  # Yield back to the reactor and allow other fibers to execute.
87
100
  def yield
88
- reactor.yield
101
+ Task.yield{reactor.yield}
89
102
  end
90
103
 
91
104
  # @attr fiber [Fiber] The fiber which is being used for the execution of this task.
@@ -137,29 +150,34 @@ module Async
137
150
  # Stop the task and all of its children.
138
151
  # @return [void]
139
152
  def stop
140
- if self.stopping?
141
- # If we are already stopping this task... don't try to stop it again.
142
- return true
143
- elsif self.running?
144
- @status = :stopping
145
-
153
+ if self.stopped?
154
+ # If we already stopped this task... don't try to stop it again:
155
+ return
156
+ end
157
+
158
+ if self.running?
146
159
  if self.current?
147
160
  raise Stop, "Stopping current fiber!"
148
161
  elsif @fiber&.alive?
149
- @fiber.resume(Stop.new)
162
+ begin
163
+ @fiber.resume(Stop.new)
164
+ rescue FiberError
165
+ @reactor << Stop::Later.new(self)
166
+ end
150
167
  end
168
+ else
169
+ # We are not running, but children might be, so transition directly into stopped state:
170
+ stop!
151
171
  end
152
- ensure
153
- @children&.each(&:stop)
154
172
  end
155
-
173
+
156
174
  # Lookup the {Task} for the current fiber. Raise `RuntimeError` if none is available.
157
175
  # @return [Async::Task]
158
176
  # @raise [RuntimeError] if task was not {set!} for the current fiber.
159
177
  def self.current
160
178
  Thread.current[:async_task] or raise RuntimeError, "No async task available!"
161
179
  end
162
-
180
+
163
181
  # Check if there is a task defined for the current fiber.
164
182
  # @return [Async::Task, nil]
165
183
  def self.current?
@@ -175,7 +193,7 @@ module Async
175
193
  def running?
176
194
  @status == :running
177
195
  end
178
-
196
+
179
197
  # Whether we can remove this node from the reactor graph.
180
198
  # @return [Boolean]
181
199
  def finished?
@@ -217,7 +235,9 @@ module Async
217
235
  end
218
236
 
219
237
  def stop!
238
+ # logger.debug(self) {"Task was stopped with #{@children.size} children!"}
220
239
  @status = :stopped
240
+ @children&.each(&:stop)
221
241
  end
222
242
 
223
243
  def make_fiber(&block)
@@ -227,7 +247,7 @@ module Async
227
247
  begin
228
248
  @result = yield(self, *args)
229
249
  @status = :complete
230
- # logger.debug("Task #{self} completed normally.")
250
+ # logger.debug(self) {"Task was completed with #{@children.size} children!"}
231
251
  rescue Stop
232
252
  stop!
233
253
  rescue StandardError => error
@@ -235,7 +255,7 @@ module Async
235
255
  rescue Exception => exception
236
256
  fail!(exception, true)
237
257
  ensure
238
- # logger.debug("Task #{self} closing: #{$!}")
258
+ # logger.debug(self) {"Task ensure $!=#{$!} with #{@children.size} children!"}
239
259
  finish!
240
260
  end
241
261
  end
@@ -254,7 +274,7 @@ module Async
254
274
  @finished.signal(@result)
255
275
  end
256
276
  end
257
-
277
+
258
278
  # Set the current fiber's `:async_task` to this task.
259
279
  def set!
260
280
  # This is actually fiber-local:
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Async
22
- VERSION = "1.20.1"
22
+ VERSION = "1.21.0"
23
23
  end
@@ -24,9 +24,29 @@ module Async
24
24
  # Represents an asynchronous IO within a reactor.
25
25
  class Wrapper
26
26
  class Cancelled < StandardError
27
+ class From
28
+ def initialize
29
+ @backtrace = caller[5..-1]
30
+ end
31
+
32
+ attr :backtrace
33
+
34
+ def cause
35
+ nil
36
+ end
37
+
38
+ def message
39
+ "Cancelled"
40
+ end
41
+ end
42
+
27
43
  def initialize
28
44
  super "The operation has been cancelled!"
45
+
46
+ @cause = From.new
29
47
  end
48
+
49
+ attr :cause
30
50
  end
31
51
 
32
52
  # wait_readable, wait_writable and wait_any are not re-entrant, and will raise this failure.
@@ -0,0 +1,28 @@
1
+ # Copyright, 2017, 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 "../async/reactor"
22
+
23
+ module Kernel
24
+ # Run the given block of code in a task, asynchronously, creating a reactor if necessary.
25
+ def Async(*args, &block)
26
+ ::Async::Reactor.run(*args, &block)
27
+ end
28
+ end
@@ -0,0 +1,32 @@
1
+ # Copyright, 2017, 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 "../async/reactor"
22
+
23
+ module Kernel
24
+ # Run the given block of code synchronously, but within a reactor if not already in one.
25
+ def Sync(&block)
26
+ if task = ::Async::Task.current?
27
+ yield
28
+ else
29
+ ::Async::Reactor.run(&block).wait
30
+ end
31
+ end
32
+ end
@@ -41,5 +41,30 @@ RSpec.describe Async::Condition do
41
41
  task.stop
42
42
  end
43
43
 
44
+ it 'can stop nested task' do
45
+ producer = nil
46
+
47
+ consumer = reactor.async do |task|
48
+ condition = Async::Condition.new
49
+
50
+ producer = task.async do |subtask|
51
+ subtask.yield
52
+ condition.signal
53
+ subtask.sleep(10)
54
+ end
55
+
56
+ condition.wait
57
+ expect do
58
+ producer.stop
59
+ end.to_not raise_error
60
+ end
61
+
62
+ consumer.wait
63
+ producer.wait
64
+
65
+ expect(producer.status).to be :stopped
66
+ expect(consumer.status).to be :complete
67
+ end
68
+
44
69
  it_behaves_like Async::Condition
45
70
  end
@@ -54,7 +54,7 @@ RSpec.describe Async::Node do
54
54
  it "can print hierarchy to bufffer" do
55
55
  subject.print_hierarchy(buffer)
56
56
 
57
- expect(lines.count).to be 2
57
+ expect(lines.size).to be 2
58
58
 
59
59
  expect(lines[0]).to be =~ /#<Async::Node:0x\h+>\n/
60
60
  expect(lines[1]).to be =~ /\t#<Async::Node:0x\h+>\n/
@@ -1,5 +1,25 @@
1
+ # Copyright, 2019, 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.
1
20
 
2
21
  require 'benchmark/ips'
22
+ require 'async'
3
23
 
4
24
  RSpec.describe Async::Wrapper do
5
25
  let(:pipe) {IO.pipe}
@@ -181,7 +181,7 @@ RSpec.describe Async::Task do
181
181
  expect(task).to be_stopped
182
182
  end
183
183
 
184
- it "should kill direct child" do
184
+ it "should stop direct child" do
185
185
  parent_task = child_task = nil
186
186
 
187
187
  reactor.async do |task|
@@ -221,6 +221,27 @@ RSpec.describe Async::Task do
221
221
  bottom_task.stop
222
222
  expect(top_task.children).to include(middle_task)
223
223
  end
224
+
225
+ it "can stop resumed task" do
226
+ items = [1, 2, 3]
227
+
228
+ Async do
229
+ condition = Async::Condition.new
230
+
231
+ producer = Async do |subtask|
232
+ while item = items.pop
233
+ subtask.yield # (1) Fiber.yield, (3) Reactor -> producer.resume
234
+ condition.signal(item) # (4) consumer.resume(value)
235
+ end
236
+ end
237
+
238
+ value = condition.wait # (2) value = Fiber.yield
239
+ expect(value).to be == 3
240
+ producer.stop # (5) [producer is resumed already] producer.stop
241
+ end
242
+
243
+ expect(items).to be == [1]
244
+ end
224
245
  end
225
246
 
226
247
  describe '#sleep' do
@@ -21,14 +21,6 @@
21
21
  require 'async'
22
22
 
23
23
  RSpec.describe Async do
24
- describe '#Async' do
25
- it "can run an asynchronous task" do
26
- Async do |task|
27
- expect(task).to be_a Async::Task
28
- end
29
- end
30
- end
31
-
32
24
  describe '.run' do
33
25
  it "can run an asynchronous task" do
34
26
  Async.run do |task|
@@ -0,0 +1,31 @@
1
+ # Copyright, 2019, 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 'kernel/async'
22
+
23
+ RSpec.describe Async do
24
+ describe '#Async' do
25
+ it "can run an asynchronous task" do
26
+ Async do |task|
27
+ expect(task).to be_a Async::Task
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,49 @@
1
+ # Copyright, 2019, 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 'kernel/sync'
22
+
23
+ RSpec.describe Kernel do
24
+ describe '#Sync' do
25
+ let(:value) {10}
26
+
27
+ it "can run a synchronous task" do
28
+ result = Sync do
29
+ expect(Async::Task.current).to_not be nil
30
+
31
+ next value
32
+ end
33
+
34
+ expect(result).to be == value
35
+ end
36
+
37
+ it "can run inside reactor" do
38
+ Async do |task|
39
+ result = Sync do
40
+ expect(Async::Task.current).to be task
41
+
42
+ next value
43
+ end
44
+
45
+ expect(result).to be == value
46
+ end
47
+ end
48
+ end
49
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.20.1
4
+ version: 1.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-14 00:00:00.000000000 Z
11
+ date: 2019-09-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nio4r
@@ -132,6 +132,7 @@ extensions: []
132
132
  extra_rdoc_files: []
133
133
  files:
134
134
  - ".editorconfig"
135
+ - ".github/FUNDING.yml"
135
136
  - ".gitignore"
136
137
  - ".rspec"
137
138
  - ".travis.yml"
@@ -142,12 +143,18 @@ files:
142
143
  - Rakefile
143
144
  - async.gemspec
144
145
  - benchmark/async_vs_lightio.rb
146
+ - benchmark/fiber_count.rb
147
+ - benchmark/thread_count.rb
148
+ - benchmark/thread_vs_fiber.rb
145
149
  - examples/async_method.rb
146
150
  - examples/callback/loop.rb
147
151
  - examples/capture/README.md
148
152
  - examples/capture/capture.rb
149
153
  - examples/fibers.rb
154
+ - examples/queue/producer.rb
150
155
  - examples/sleep_sort.rb
156
+ - examples/stop/condition.rb
157
+ - examples/stop/sleep.rb
151
158
  - gems/event.gemfile
152
159
  - lib/async.rb
153
160
  - lib/async/clock.rb
@@ -163,6 +170,8 @@ files:
163
170
  - lib/async/task.rb
164
171
  - lib/async/version.rb
165
172
  - lib/async/wrapper.rb
173
+ - lib/kernel/async.rb
174
+ - lib/kernel/sync.rb
166
175
  - logo.png
167
176
  - logo.svg
168
177
  - papers/1982 Grossman.pdf
@@ -182,6 +191,8 @@ files:
182
191
  - spec/async/wrapper_spec.rb
183
192
  - spec/async_spec.rb
184
193
  - spec/enumerator_spec.rb
194
+ - spec/kernel/async_spec.rb
195
+ - spec/kernel/sync_spec.rb
185
196
  - spec/spec_helper.rb
186
197
  homepage: https://github.com/socketry/async
187
198
  licenses:
@@ -202,7 +213,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
202
213
  - !ruby/object:Gem::Version
203
214
  version: '0'
204
215
  requirements: []
205
- rubygems_version: 3.0.3
216
+ rubygems_version: 3.0.4
206
217
  signing_key:
207
218
  specification_version: 4
208
219
  summary: Async is an asynchronous I/O framework based on nio4r.
@@ -222,4 +233,6 @@ test_files:
222
233
  - spec/async/wrapper_spec.rb
223
234
  - spec/async_spec.rb
224
235
  - spec/enumerator_spec.rb
236
+ - spec/kernel/async_spec.rb
237
+ - spec/kernel/sync_spec.rb
225
238
  - spec/spec_helper.rb