Victor
Victor

Reputation: 13368

Concurrent Rails iteration/operation

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

Answers (1)

Chris Heald
Chris Heald

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

Related Questions