Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: Wait for all threads completed using join and ThreadsWait.all_waits - what the difference?

Consider the following example:

threads = []

(0..10).each do |_|
  threads << Thread.new do
    # do async staff there
    sleep Random.rand(10)
  end
end

Then there is 2 ways to wait when it's done:

  1. Using join:

    threads.each(&:join)
    
  2. Using ThreadsWait:

    ThreadsWait.all_waits(threads)
    

Is there any difference between these two ways of doing this?

I know that the ThreadsWait class has other useful methods. And asking especially about all_waits method.

like image 283
skywinder Avatar asked May 22 '15 15:05

skywinder


People also ask

What does thread join do in Ruby?

Calling Thread. join blocks the current (main) thread. However not calling join results in all spawned threads to be killed when the main thread exits.

Is Ruby multithreaded or single threaded?

Multi-threading is the most useful property of Ruby which allows concurrent programming of two or more parts of the program for maximizing the utilization of CPU. Each part of a program is called Thread. So, in other words, threads are lightweight processes within a process.


1 Answers

The documentation clearly states that all_waits will execute any passed block after each thread's execution; join doesn't offer anything like this.

require "thwait"

threads = [Thread.new { 1 }, Thread.new { 2 }]

ThreadsWait.all_waits(threads) do |t|
  puts "#{t} complete."
end # will return nil

# output:
# #<Thread:0x00000002773268> complete.
# #<Thread:0x00000002772ea8> complete.

To accomplish the same with join, I imagine you would have to do this:

threads.each do |t|
  t.join
  puts "#{t} complete."
end # will return threads

Apart from this, the all_waits methods eventually calls the join_nowait method which processes each thread by calling join on it.

Without any block, I would imagine that directly using join would be faster since you would cut back on all ThreadsWait methods leading up to it. So I gave it a shot:

require "thwait"
require "benchmark"

loops = 100_000
Benchmark.bm do |x|
  x.report do
    loops.times do
      threads = [Thread.new { 2 * 1000 }, Thread.new { 4 * 2000 }]
      threads.each(&:join)
    end
  end

  x.report do
    loops.times do
      threads = [Thread.new { 2 * 1000 }, Thread.new { 4 * 2000 }]
      ThreadsWait.all_waits(threads)
    end
  end
end

# results:
# user       system     total       real
# 4.030000   5.750000   9.780000  ( 5.929623 )
# 12.810000  17.060000  29.870000 ( 17.807242 )
like image 128
SHS Avatar answered Sep 28 '22 06:09

SHS