First of all I am Ruby newby and I am trying to learn the language. The best way I know to learn something is to actually solve problems with it. So I took a simple string problem and implemented solution1 like this:
def similarities(str)
result = str.length
(1..str.length - 1).each { |start|
str2 = str[start..-1]
index = 0
str2.split(//).each do |c|
break if c != str[index, 1]
index += 1
end
result += index
}
result
end
It then occurred to me that this is perfect match for a “parallel foreach” kind of think. So I came up with solution2
def similarities(str)
result = str.length
threads = []
(1..str.length - 1).each { |start|
str2 = str[start..-1]
threads << Thread.new { calculate(str, str2) }
}
threads.each { |t| t.join; result += t["index"] }
result
end
def calculate(str, str2)
index = 0
str2.split(//).each do |c|
break if c != str[index, 1]
index += 1
end
Thread.current["index"] = index
end
To my surprise solution2 took about 8 times more time to run than solution1 on the exact same input. Why ?
Thanks,
Context switching is expensive, much more so than the actual, fairly trivial calculation you’re implementing. If you were to profile this, 90% of your time would probably be eaten up by thread-related system calls.
Edit: Also, if you’re using CRuby/MRI, you’re going to be limited by the lack of true multithreading. See Does ruby have real multithreading? for details.