Skip to content

Instantly share code, notes, and snippets.

@oprypin
Last active March 9, 2024 18:02
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save oprypin/00953b336673719dba25 to your computer and use it in GitHub Desktop.
Save oprypin/00953b336673719dba25 to your computer and use it in GitHub Desktop.
module Indexable(T)
def threadpool_map(workers : Int = 8, chunk_size : Int? = nil, &func : T -> R) forall T, R
mutex = Thread::Mutex.new
cs = chunk_size || (self.size**0.5).ceil.to_i
Array(R).build(self.size) do |result|
index = 0
threads = Array.new(workers) {
Thread.new do
a = b = 0
loop do
mutex.synchronize do
a = index
b = (index += cs)
end
if b > self.size
break if a >= self.size
b = self.size
end
(a...b).each do |i|
result[i] = func.call(self[i])
end
end
end
}
threads.map &.join
self.size
end
end
end
require "./threadpool_map"
def is_prime(n)
return false if n % 2 == 0
sqrt_n = Math.sqrt(n).to_i
(3..sqrt_n).step(2) do |i|
return false if n % i == 0
end
true
end
require "benchmark"
[
(1_000_000_001..1_000_100_000).to_a,
(1..3_000_000).to_a,
[337] * 10_000_000,
].each do |numbers|
Benchmark.bm do |r|
a = b = nil
r.report "thr" do
a = numbers.threadpool_map(&->is_prime(Int32))
end
r.report "map" do
b = numbers.map(&->is_prime(Int32))
end
raise "error" unless a == b
end
end
$ crystal run --release z-benchmark.cr
user system total real
thr 0.240000 0.000000 0.240000 ( 0.064314)
map 0.240000 0.000000 0.240000 ( 0.241106)
user system total real
thr 0.450000 0.000000 0.450000 ( 0.143259)
map 0.440000 0.000000 0.440000 ( 0.443335)
user system total real
thr 0.250000 0.000000 0.250000 ( 0.065117)
map 0.230000 0.010000 0.240000 ( 0.233782)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment