From: Robert Klemme Date: 2008-01-01T21:00:03+09:00 Subject: Re: Why not call Thread.join? On 01.01.2008 03:25, Ian Whitlock wrote: > 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!!!! Sorry to say that, but this is a bogus solution. Using sleep for this is not a good idea: if tasks take longer then you will loose output anyway or even risk that some tasks are not finished properly, if all tasks are finished much faster you'll waste time. The thread killing is the exact reason why #each_simultaneously was built to return an Array of Thread objects. That way you can join all the threads. > # 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. I prefer the solution that does not join in the method but returns Threads. If you think about it, that version is significantly more flexible. You can join those threads immediately an_enum.each_simultaneously {|e| ... }.each {|th| th.join} but you can as well do some work in between threads = an_enum.each_simultaneously {|e| ... } do_some_work ... threads.each {|th| th.join} > 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. When I was initially confronted with multithreading it also took me a while. For me at the time it was difficult to not confuse Thread objects with threads. This was in Java which decouples Thread object creation and thread execution, which probably makes it a bit easier to grasp the concepts. It is important to keep this distinction in mind: a Thread object in a way is an object that is like any other object just with the added twist that it *may* be associated with an independent thread of execution (i.e. in Java it is not associated until the thread starts and after the thread terminates, in Ruby the association is there right from the start because threads are started immediately and lasts until the thread terminates). Kind regards robert