async 1.20.1 → 1.21.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: 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