Reputation: 13368
Usually we iterate an array one by one:
a = [1, 2, 3, 4]
b = []
a.each do |x|
b << x * 5
end
b = [5, 10, 15, 20]
What if I don't care about the order of the contents in the array, but want to increase the speed of the iteration by concurrently running the multiplication operation? For example, such results are acceptable:
b = [15, 10, 5, 20] # or
b = [5, 20, 15, 10] # or
b = [20, 15, 5, 10]
How do I do that?
Upvotes: 0
Views: 103
Reputation: 62638
MRI doesn't do true multicore parallelism due to the GIL; threading doesn't actually get you performance improvements on CPU-bound tasks (though it definitely does on IO-bound tasks); you need to be running JRuby or Rubinius to get parallelism for CPU-bound tasks, since they can actually distribute work across multiple cores concurrently.
That said, assuming you are running a VM that offers true parallelism:
b = a.map {|x|
Thread.new {
Thread.current[:out] = x * 5
}
}.map {|t| t.join; t[:out] }
(This code is very ugly and should be refactored for actual usage. It will also return results in the order that the threads were created, while still parallelizing the task.)
The major points here are 1) propagation of return values in a thread local variable (so you don't have to perform a possibly-unatomic operation on a shared value; if you want to do that you need to introduce a Mutex), and 2) calling #join
on each thread created, so that we are sure that each thread created has finished running.
Upvotes: 4