Newbie question regarding threads and system commands

Sorry if I'm bothering you all again... This is my first program that runs
a) threads and b) `system commands`, so I apologize for being a newbie. What
I'm trying to do is ping multiple parts of a site to help an tech support
guy (me) in figuring out where a point of failure is at a remote location.
The reason I'm using threads: I want it to be faster than me typing across
multiple cmd windows. The problem: it's taking 15+ seconds when it works.
I've been tinkering now with it for a few days, and I either get the program
to end in 1 second (killing the child threads before they are done) or I get
the 15 second problem. I'm just not real sure where to put the
Thread.jointo make this run smoothly - nor am I sure that
thread.join is the solution.

Joel VanderWerf suggested mapping stuff, but I'm not doing this by IP
address (his solution the other day involved ping 192.168.1.#{i}) and I
couldn't quite figure out how to modify his code to fit mine.

code (with some stuff obfuscated)

def pingsite(site, type)
result = `ping -n 4 #{site}-#{type}-1`.chomp
return result
end
puts "What site?"
sitelocation = gets.chomp
t0 = Time.now
data = ""
sitetype=["something", "somethingelse", "again", "more", "otherstuff"]
sitetype.each do |type|
type=Thread.new do
  puts pingsite(sitelocation, type)
end
type.join
end
#sitetype.join
t1 = Time.now
puts "Finished in #{t1 - t0} seconds"

Output:
Finished in 14.711 seconds

with sitetype.join uncommented and type.join commented, I get this:
What site?
0110
Finished in 1.051 seconds

Can someone explain to me what I'm doing wrong?

This is one possible solution, which seems to work fine (it takes 3.14
seconds on my system to ping 3 web sites). Bottom line: you need to keep
a list of the threads and join all of them in the calling code. Hope
this helps. I recommend that you get a copy of the "Pickaxe" book
(Programming Ruby: The Pragmatic Programmers Guide, 2nd edition) , which
has a very good section on threading and lots of examples. In the
meantime, you can read this from the first edition:

http://www.rubycentral.com/book/tut_threads.html

···

-------------
require 'thread'

class SystemExecutor
  # Returns array [[cmd, response], [cmd, response], ...]
  def SystemExecutor.run(system_cmd_list)
    thread_list = []
    system_response_list = []
    srl_mutex = Mutex.new

    system_cmd_list.each do |cmd|
      thread_list << Thread.new do
        begin
          response = %x{ #{cmd} }
          srl_mutex.synchronize do
            system_response_list << [cmd, response]
          end
        rescue Exception => exc
          srl_mutex.synchronize do
            system_response_list << [cmd, exc]
          end
        end
      end
    end

    thread_list.each { |thr| thr.join }
    system_response_list
  end
end

puts "Starting ping"
start_time = Time.now
resp = SystemExecutor.run(['ping www.ruby-forum.org', 'ping
www.sourceforge.net', 'ping www.google.com'])
elapsed_time = Time.now - start_time

resp.each do |cmd, resp|
  puts "Command: #{cmd}", '-' * 20
  puts "Response:\n", '-' * 20, "#{resp}"
end

puts "Elapsed time: #{elapsed_time} seconds."

--
Posted via http://www.ruby-forum.com/.

Maybe there's something wrong with my system here at work then.... because
this took 11.something seconds to run on my machine. I'll test again from
home (both xp pro systems)

···

On 11/24/06, Edwin Fine <efine145-nospam01@usa.net> wrote:

This is one possible solution, which seems to work fine (it takes 3.14
seconds on my system to ping 3 web sites). Bottom line: you need to keep
a list of the threads and join all of them in the calling code. Hope
this helps. I recommend that you get a copy of the "Pickaxe" book
(Programming Ruby: The Pragmatic Programmers Guide, 2nd edition) , which
has a very good section on threading and lots of examples. In the
meantime, you can read this from the first edition:

http://www.rubycentral.com/book/tut_threads.html
-------------
require 'thread'

class SystemExecutor
# Returns array [[cmd, response], [cmd, response], ...]
def SystemExecutor.run(system_cmd_list)
   thread_list =
   system_response_list =
   srl_mutex = Mutex.new

   system_cmd_list.each do |cmd|
     thread_list << Thread.new do
       begin
         response = %x{ #{cmd} }
         srl_mutex.synchronize do
           system_response_list << [cmd, response]
         end
       rescue Exception => exc
         srl_mutex.synchronize do
           system_response_list << [cmd, exc]
         end
       end
     end
   end

   thread_list.each { |thr| thr.join }
   system_response_list
end

puts "Starting ping"
start_time = Time.now
resp = SystemExecutor.run(['ping www.ruby-forum.org', 'ping
www.sourceforge.net', 'ping www.google.com'])
elapsed_time = Time.now - start_time

resp.each do |cmd, resp|
puts "Command: #{cmd}", '-' * 20
puts "Response:\n", '-' * 20, "#{resp}"
end

puts "Elapsed time: #{elapsed_time} seconds."

--
Posted via http://www.ruby-forum.com/\.

As it turns out, your program runs fine (<4 seconds) if I change the ping
destinations to something on the internal network. Looks like a router is
misconfigured somewhere. Thanks!

···

On 11/25/06, Jason Mayer <slamboy@gmail.com> wrote:

Maybe there's something wrong with my system here at work then.... because
this took 11.something seconds to run on my machine. I'll test again from
home (both xp pro systems)

On 11/24/06, Edwin Fine <efine145-nospam01@usa.net> wrote:
>
> This is one possible solution, which seems to work fine (it takes 3.14
> seconds on my system to ping 3 web sites). Bottom line: you need to keep
> a list of the threads and join all of them in the calling code. Hope
> this helps. I recommend that you get a copy of the "Pickaxe" book
> (Programming Ruby: The Pragmatic Programmers Guide, 2nd edition) , which
> has a very good section on threading and lots of examples. In the
> meantime, you can read this from the first edition:
>
> http://www.rubycentral.com/book/tut_threads.html
> -------------
> require 'thread'
>
> class SystemExecutor
> # Returns array [[cmd, response], [cmd, response], ...]
> def SystemExecutor.run(system_cmd_list)
> thread_list =
> system_response_list =
> srl_mutex = Mutex.new
>
> system_cmd_list.each do |cmd|
> thread_list << Thread.new do
> begin
> response = %x{ #{cmd} }
> srl_mutex.synchronize do
> system_response_list << [cmd, response]
> end
> rescue Exception => exc
> srl_mutex.synchronize do
> system_response_list << [cmd, exc]
> end
> end
> end
> end
>
> thread_list.each { |thr| thr.join }
> system_response_list
> end
>
> puts "Starting ping"
> start_time = Time.now
> resp = SystemExecutor.run(['ping www.ruby-forum.org', 'ping
> www.sourceforge.net', 'ping www.google.com'])
> elapsed_time = Time.now - start_time
>
> resp.each do |cmd, resp|
> puts "Command: #{cmd}", '-' * 20
> puts "Response:\n", '-' * 20, "#{resp}"
> end
>
> puts "Elapsed time: #{elapsed_time} seconds."
>
> --
> Posted via http://www.ruby-forum.com/\.
>