Skip to content

Instantly share code, notes, and snippets.

@tenderlove
Last active October 29, 2024 21:42
Show Gist options
  • Save tenderlove/fc923f948537bd8ab913f4f5205f4288 to your computer and use it in GitHub Desktop.
Save tenderlove/fc923f948537bd8ab913f4f5205f4288 to your computer and use it in GitHub Desktop.
##
# Test how long it takes to deflate bytes using different concurrency
# primitives in Ruby.
#
# Output on my machine:
#
# $ ruby test.rb
# 2 iterations (no parallelism): 11.86 seconds
# 2 iterations (Async): 11.88 seconds
# 2 iterations (Thread): 6.00 seconds
#
# Running Zlib.deflate runs _faster_ with threads than it does with Fibers.
# Why? Zlib is a C extension that does purely CPU bound work. The C extension
# releases the GVL which allows the system to schedule another thread.
#
# Async's scheduler only switches on IO blocking, so no CPU bound Fiber can
# run in parallel. Releasing the GVL doesn't allow the Fiber scheduler to
# schedule other work.
require "zlib"
require "async"
N = (ENV["N"] || 2).to_i
def measure
x = Process.clock_gettime(Process::CLOCK_MONOTONIC)
yield
Process.clock_gettime(Process::CLOCK_MONOTONIC) - x
end
def work str
Zlib.deflate str
end
str = Random.new.bytes(1024*1024*400)
time = measure { N.times { work(str) } }
puts "#{N} iterations (no parallelism): #{sprintf("%.2f", time)} seconds"
Async {
time = measure {
N.times.map { Async { work(str) } }.map(&:wait)
}
puts "#{N} iterations (Async): #{sprintf("%.2f", time)} seconds"
}
time = measure {
N.times.map { Thread.new { work(str) } }.map(&:join)
}
puts "#{N} iterations (Thread): #{sprintf("%.2f", time)} seconds"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment