From: Ian Whitlock Date: 2008-01-01T11:25:12+09:00 Subject: Re: Why not call Thread.join? Craig Beck 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 -- Posted via http://www.ruby-forum.com/.