Craig B. wrote:
module Enumerable
print “Completed operation for #{e}!\n”
end
Completed operation for 8!
Completed operation for 7!
Completed operation for 9!
Time.now - start_time # => 5.009334
try looking at the crude timeline below…
sec 0 1 2 3 4 5
6 7
|---------|---------|---------|---------|---------|---------|---------|
main ====@=================================================
t[1] ===================================================
t[2] ===================================================
t[3] ===================================================
The @ on the main thread represents when the t.join gets called. It
waits in this simple case for t[1] to finish it’s work (sleeping for 5
seconds), then waits for t[2]. As t[2] has also been doing work all
this time, it only blocks the main thread for another 0.1 sec before
finishing. Same for t[3]. So this contrived example it takes 5 seconds
- whatever overhead for starting threads.
You could throw more instrumentation in there if you wish and do
things like adding additional calls to sleep to simulate extra thread
overhead to make it more obvious.
To me the important point in addition to the parallelism is that, when
run in batch mode, say with SciTE, main takes less than a second and
kills all the threads. Hence the messages are never seen. To see
the reports you have to do something like
start_time = Time.now
[7,8,9].each_simultaneously do |e|
sleep(5) # Simulate a long, high-latency operation
print “Completed operation for #{e}!\n”
end
sleep 5 #######main must take at least 5 seconds!!!
Completed operation for 8!
Completed operation for 7!
Completed operation for 9!
Time.now - start_time # => 5.009334
to guarantee that the threads have 5 seconds to finish
their operation. Or you can use
module Enumerable
def each_simultaneously
collect {|e| Thread.new {yield e}}.each {|t| t.join}
end
end
which guarantees that the threads will finish before
control is returned to main.
In reality it is also important that threads spend a large
part of their operation just waiting when there is only one
CPU.
I think the problem arose because the example on page 760
of the Ruby Cookbook does not mention the necessity of the
main thread lasting long enough and does not show code to
make it happen.
I realize that much of this may have been obvious to some
who replied, but as a newby it wasn’t to me until I read
the section and played with the code.
Ian