2

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,

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
Calin
  • 6,661
  • 7
  • 49
  • 80

1 Answers1

3

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.

Community
  • 1
  • 1
Yes - that Jake.
  • 16,725
  • 14
  • 70
  • 96