Creating threads can be slow?

Hello!

I am currently load testing a system. Under load, the couple of lines
below where I am creating threads are becoming slow:

temp = []
foo_array.each do |foo|
temp << Thread.new (foo) { |e| …}
end

I have put a “timer” around these few lines. I know it is completely
dependent on the system but just to give an idea it can take more than
20s for <> 100 threads. Just the code above. I am using 1.8.7 and the
standard MRI.

Am I missing something? Do threads involve a significant overhead?

Thanks a lot,
Pierre

On Fri, Oct 21, 2011 at 5:41 PM, wam r. [email protected] wrote:

I am currently load testing a system. Under load, the couple of lines
below where I am creating threads are becoming slow:

Well, under load anything is slow, isn’t it? :slight_smile:

temp = []
foo_array.each do |foo|
temp << Thread.new (foo) { |e| …}
end

Btw, you can simplify that to

temp = foo_array.map {|foo| Thread.new(foo) {|e| …}}

I have put a “timer” around these few lines. I know it is completely
dependent on the system but just to give an idea it can take more than
20s for <> 100 threads. Just the code above. I am using 1.8.7 and the
standard MRI.

Am I missing something? Do threads involve a significant overhead?

Generally, i.e. in many common programming languages, creating threads
is quite an expensive operation (compared to a method call for
example) because of the overhead involved (allocating the stack and
other things which need to be done). Having said that you might want
to try 1.9* versions of Ruby which are generally faster than 1.8*.

Kind regards

robert

On 10/21/2011 05:49 PM, Robert K. wrote:

example) because of the overhead involved (allocating the stack and
other things which need to be done). Having said that you might want
to try 1.9* versions of Ruby which are generally faster than 1.8*.

Kind regards

robert

And just in case Ruby 1.9* is not an option, you may want to try Ruby
Enterprise Edition which “could” be faster than MRI (untested guess, but
i had cases where it produced significant speedups so it may be worth a
try).

http://www.rubyenterpriseedition.com/

Greets, Chris

On Fri, Oct 21, 2011 at 8:41 AM, wam r. [email protected] wrote:

I have put a “timer” around these few lines. I know it is completely
dependent on the system but just to give an idea it can take more than
20s for <> 100 threads. Just the code above. I am using 1.8.7 and the
standard MRI.

Something’s wrong if it takes 20s to create 100 threads. I develop a
threading library for Ruby (Celluloid) and benchmark thread creation
speed
on Ruby regularly. Thread creation time should be in the realm of
500-1000
threads/sec on modern hardware.

Hi guys,

It is difficult to describe the load: it is a Rails app with many moving
parts. By “loading” I mean I am sending 10 to 20 requests at once (and
repeat) just to see how it reacts.

I have been able to “track” the key time consuming parts in my code.
There are three of them:

  • one linked to DB requests
  • one linked to heavy computations (some optimization algos)
  • the third one: the thread creation above.

The more I load, the more time each of these take - it is very
correlated.
I know how to optimize the first two, but not the last one. It doesn’t
seem there is anything I can do (besides switching to a different Ruby
which I can’t unfortunately).

But Robert it seems you are right: it is just CPU intensive. I had a
chance to add another box to the cluster this week-end and it makes a
huge difference. I just did not realize that creating threads would be
that CPU intensive.

Anyway thanks a lot for your help on this.

Pierre

On Fri, Oct 21, 2011 at 6:52 PM, Tony A. [email protected]
wrote:

threads/sec on modern hardware.
He said “under load” - which is pretty unspecific. If a system is
under serious load, almost anything can take ages.

Pierre, can you be more specific about the nature of the load etc.?
If you are on a Linux system, you could use dstat to monitor various
aspects of load.

Kind regards

robert

On Mon, Oct 24, 2011 at 2:26 PM, wam r. [email protected] wrote:

  • the third one: the thread creation above.

The more I load, the more time each of these take - it is very
correlated.

Hi there.

Keep in mind Ruby 1.8.7 doesn’t have real threads, it has “green
threads”
which are scheduled by the VM.

If you are using database drivers that make blocking system calls, they
have
the potential to block the entire VM as 1.8.7 can only make one system
call
at once.

If you are making heavy use of threads in Ruby, you should also consider
moving to JRuby or Rubinius, which both support true concurrent
multithreading with no Global Interpreter Lock.

On Mon, Oct 24, 2011 at 11:26 PM, wam r. [email protected]
wrote:

  • the third one: the thread creation above.
    that CPU intensive.

Anyway thanks a lot for your help on this.

You’re welcome! One other measure which may help you is to limit
concurrency by using a thread pool fed from a queue. That way you
avoid thread creation overhead for every work item plus you limit
concurrency - usually it does not make much sense to go beyond a
certain point, with real native threads that’s related to the number
of cores.

And you should definitively switch to 1.9. If you wait a few days /
weeks you can directly jump on 1.9.3 which already has a release
candidate out.

Kind regards

robert