Skip to content

Instantly share code, notes, and snippets.

@pandwoter
Last active April 19, 2022 11:37
Show Gist options
  • Save pandwoter/7a28fb9f52c0931048febfb8b453139c to your computer and use it in GitHub Desktop.
Save pandwoter/7a28fb9f52c0931048febfb8b453139c to your computer and use it in GitHub Desktop.
require 'concurrent'
require 'benchmark'
class Request
class << self
def make(num)
@body = Faraday.get("https://jsonplaceholder.typicode.com/todos/#{num}").body
self
end
def to_json
JSON(@body)
end
end
end
class PromisesExecutor
def initialize(amount)
@amount = amount
end
def call
promises = @amount.times.map { |i| Concurrent::Promises.future(i) { |i| Request.make(i).to_json } }
Concurrent::Promises.zip(*promises).value!
end
end
class SeqExecutor
def initialize(amount)
@amount = amount
end
def call
@amount.times.map { |i| Request.make(i).to_json }
end
end
class WorkerPool
TERMINATOR = :abort
def initialize(amount)
@amount = amount
@jobs = Queue.new
@results = Concurrent::Array.new
@pool = @amount.times.map do |i|
Thread.new(i) do |num|
Thread.current.name = "worker-#{num}"
loop do
job, args = @jobs.pop
break if args.first == TERMINATOR
@results << job.call(*args)
end
end
end
end
def schedule(*args, &block)
@jobs << [block, args]
end
def shutdown
@amount.times { schedule TERMINATOR }
@pool.map(&:join)
end
end
pool_4 = WorkerPool.new(4)
pool_8 = WorkerPool.new(8)
pool_10 = WorkerPool.new(10)
pool_16 = WorkerPool.new(16)
pool_32 = WorkerPool.new(32)
def run_thread_pool(pool)
30.times { |i| pool.schedule(i) { |i| Request.make(i).to_json } }
pool.shutdown
pool.instance_variable_get(:@results)
end
Benchmark.bm do |experiment|
experiment.report('custom threadpool: (4)') { run_thread_pool(pool_4) }
experiment.report('custom threadpool: (8)') { run_thread_pool(pool_8) }
experiment.report('custom threadpool: (10)') { run_thread_pool(pool_10) }
experiment.report('custom threadpool: (16)') { run_thread_pool(pool_16) }
experiment.report('custom threadpool: (32)') { run_thread_pool(pool_32) }
end
Benchmark.bm do |experiment|
experiment.report('seq:') { SeqExecutor.new(30).call }
experiment.report('async via promises:') { PromisesExecutor.new(30).call }
experiment.report('custom threadpool:') { run_thread_pool(pool_32) }
end
@pandwoter
Copy link
Author

pandwoter commented Apr 19, 2022

       user     system      total        real
seq:  0.144788   0.030441   0.175229 (  4.008818)
async via promises:  0.085559   0.020963   0.106522 (  0.655998)
custom threadpool:  0.100604   0.017977   0.118581 (  0.403523)

@pandwoter
Copy link
Author

       user     system      total        real
custom threadpool: (4)  0.139250   0.031637   0.170887 (  1.237397)
custom threadpool: (8)  0.135445   0.032640   0.168085 (  0.641248)
custom threadpool: (10)  0.121258   0.027308   0.148566 (  0.492202)
custom threadpool: (16)  0.110450   0.026344   0.136794 (  0.403192)
custom threadpool: (32)  0.074541   0.019488   0.094029 (  0.219029)

@pandwoter
Copy link
Author

Intel(R) Core(TM) i5-8257U CPU @ 1.40GHz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment