Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A bunch of unsorted examples. #208

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions benchmark/respond_to_vs_hash.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

# Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

require 'benchmark/ips'

GC.disable

class FakeBody
def each
yield "Fake Body"
end
end

object = FakeBody.new

class Stream
def write(chunk)
end
end

stream = Stream.new

proc = Proc.new do |stream|
stream.write "Fake Body"
end

hash = Hash.new
10.times do |i|
hash['fake-header-i'] = i
end

hijack_hash = hash.dup
hijack_hash['rack.hijack'] = proc

Benchmark.ips do |benchmark|
benchmark.time = 1
benchmark.warmup = 1

benchmark.report("object") do |count|
while count > 0
if object.respond_to?(:call)
object.call(stream)
else
object.each{|x| stream.write(x)}
end

count -= 1
end
end

benchmark.report("proc") do |count|
while count > 0
if proc.respond_to?(:call)
proc.call(stream)
else
object.each{|x| stream.write(x)}
end

count -= 1
end
end

benchmark.report("hash") do |count|
while count > 0
if hijack = hash['rack.hijack']
hijack.call(stream)
else
object.each{|x| stream.write(x)}
end

count -= 1
end
end

benchmark.report("hijack-hash") do |count|
while count > 0
if hijack = hijack_hash['rack.hijack']
hijack.call(stream)
else
object.each{|x| stream.write(x)}
end

count -= 1
end
end

benchmark.compare!
end
46 changes: 46 additions & 0 deletions examples/duration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# frozen_string_literal: true

class Duration
def initialize(value)
@value = value
end

attr :value

SUFFIX = ["s", "ms", "μs", "ns"]

def zero?
@value.zero?
end

def to_s
return "0" if self.zero?

unit = 0
value = @value.to_f

while value < 1.0 && unit < SUFFIX.size
value = value * 1000.0
unit = unit + 1
end

return "#{value.round(2)}#{SUFFIX[unit]}"
end

def / factor
self.class.new(@value / factor)
end

def self.time
t = Process.times
return t.stime + t.utime + t.cstime + t.cutime
end

def self.measure
t = self.time

yield

return self.new(self.time - t)
end
end
10 changes: 10 additions & 0 deletions examples/scheduler/config.ru
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

require 'net/http'

run ->(env) do
response = Net::HTTP.get(URI "https://www.google.com/search?q=ruby")

count = response.scan("ruby").count

[200, [], ["Found ruby #{count} times!"]]
end
26 changes: 26 additions & 0 deletions examples/scheduler/http.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env ruby

require_relative '../../lib/async'
require_relative '../../lib/async/barrier'

require 'net/http'

terms = ['cats', 'dogs', 'sheep', 'cows']

Async do
barrier = Async::Barrier.new

terms.each do |term|
barrier.async do
Console.logger.info "Searching for #{term}"

response = Net::HTTP.get(URI "https://www.google.com/search?q=#{term}")

count = response.scan(term).count

Console.logger.info "Found #{term} #{count} times!"
end
end

barrier.wait
end
143 changes: 143 additions & 0 deletions examples/scheduler/ko1.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#!/usr/bin/env ruby

require 'fiber'
require 'io/nonblock'
require 'open-uri'

class Scheduler
def initialize
@ready = []
@waiting = [] # [[f, type, opts], ...]
end

def now
Process.clock_gettime(Process::CLOCK_MONOTONIC)
end

def wait_readable_fd(fd)
wait_readable(::IO.for_fd(fd, autoclose: false))
end

def wait_readable(io)
p wait_readable: io
Fiber.yield :wait_readable, io

true
end

def wait_any(io, events, timeout)
p [:wait_any, io, events, timeout]
case events
when IO::WAIT_READABLE
Fiber.yield :wait_readable, io
when IO::WAIT_WRITABLE
Fiber.yield :wait_writable, io
when IO::WAIT_READABLE | IO::WAIT_WRITABLE
Fiber.yield :wait_any, io
end

true
end

# Wrapper for rb_wait_for_single_fd(int) C function.
def wait_for_single_fd(fd, events, duration)
wait_any(::IO.for_fd(fd, autoclose: false), events, duration)
end

# Sleep the current task for the specified duration, or forever if not
# specified.
# @param duration [#to_f] the amount of time to sleep.
def wait_sleep(duration = nil)
Fiber.yield :sleep, self.now + duration
end

def fiber
@ready << f = Fiber.new(blocking: false){
yield
:exit
}
f
end

def schedule_ready
while f = @ready.shift
wait, opts = f.resume
case wait
when :exit
# ok
else
@waiting << [f, wait, opts]
end
end
end

def run
until @ready.empty? && @waiting.empty?
schedule_ready
next if @waiting.empty?
p @waiting
wakeup_time = nil
wakeup_fiber = nil
rs = []
ws = []
now = self.now
@waiting.each{|f, type, opt|
case type
when :sleep
t = opt
if !wakeup_time || wakeup_time > t
wakeup_time = t
wakeup_fiber = f
end
when :wait_readable
io = opt
rs << io
when :wait_writable
io = opt
ws << io
when :wait_any
io = opt
rs << io
ws << io
end
}
if wakeup_time
if wakeup_time > now
dur = wakeup_time - self.now
else
@ready << wakeup_fiber
@waiting.delete_if{|f,| f == wakeup_fiber}
end
end
pp dur
rs, ws, es = IO.select rs, ws, nil, dur
pp selected: [rs, ws, es]
[*rs, *ws].each{|io|
@waiting.delete_if{|f, type, opt|
if opt == io
p [:ready, f, io]
@ready << f
true
end
}
}
pp after: @waiting
end
end

def enter_blocking_region
#pp caller(0)
end

def exit_blocking_region
#pp caller(0)
end
end

Thread.current.scheduler = Scheduler.new

Fiber do
URI.open('http://www.ruby-lang.org/'){|f| p f.gets}
end

Thread.current.scheduler.run
46 changes: 46 additions & 0 deletions examples/scheduler/pipe.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

puts "Starting..."

require_relative '../../lib/async'
require_relative '../../lib/async/scheduler'

require 'io/nonblock'

thread = Thread.current

abort "Require Thread\#selector patch" unless thread.respond_to?(:selector)

MESSAGE = "Helloooooo World!"

Async do |task|
scheduler = Async::Scheduler.new(task.reactor)

thread.selector = scheduler

input, output = IO.pipe
input.nonblock = true
output.nonblock = true

task.async do
MESSAGE.each_char do |character|
puts "Writing: #{character}"
output.write(character)
sleep(1)
end

output.close
end

input.each_char do |character|
puts "#{Async::Clock.now}: #{character}"
end

puts "Closing"
input.close
ensure
thread.selector = nil
end

puts "Done"
12 changes: 12 additions & 0 deletions examples/scheduler/sample/config.ru
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

require 'net/http'

run ->(env) do
term = "ruby"

response = Net::HTTP.get(URI "https://www.google.com/search?q=#{term}")

count = response.scan(term).size

[200, [], ["Found #{count} times.\n"]]
end
Loading