On 10/29/2009 03:56 PM, Marc Hoeppner wrote:
> Hi,
> 
> I've been reading around a bit but couldn't find a solution that worked,
> so here goes:
> 
> I am running ruby 1.8 and want to make full use of a quad core CPU
> (64bit, Ubuntu) in a task that lends itself to multithreading/multicore
> use.
> 
> It's basically an array of objects that are each use in a fairly CPU
> intensive job, so I figured I could have 4 of them run at the same time
> , one on each CPU.
> 
> BUT...
> 
> The only reasonably understandably suggestion looked something like:
> 
> ----
> threads = 4
> my_array = [something_here]
> 
> threads.times do
>  Process.fork(a_method(my_array.shift))
> end
> 
> my_array.each do |object|
>  Process.wait(0)
>  Process.fork(a_method(object))
> end
> ---
> 
> But this still only used one CPU (and looks a bit ugly..). Is that some
> limitation of ruby (v 1.8 specifically) or am I doing something wrong?

I believe you are not using Process.fork properly.  In fact, I am 
surprised that you do not get an exception:

irb(main):001:0> Process.fork("foo")
ArgumentError: wrong number of arguments (1 for 0)
	from (irb):1:in `fork'
	from (irb):1
	from :0

Basically what you do is you do a calculation (a_method(object)) and 
_then_ you create a process.  No surprise that only one CPU is busy.

Here's something else that you could do

processes = 4

my_array.each_slice my_array.size / processes do |tasks|
   fork do
     tasks.each do |task|
       a_method(task)
     end
   end
end

Process.waitall

Drawback is that one of those processes might accidentally get all the 
easy tasks and you do not utilize CPUs optimally.  Here's another 
solution that does not have that issue

processes = 4
count = 0

my_array.each do |task|
   if count == processes
     Process.wait
     count -= 1
   end

   fork do
     a_method(task)
   end
   count += 1
end

Process.waitall

You can see that it works with this example:

processes = 4
count = 0

10.times do |task|
   if count == processes
     Process.wait
     count -= 1
   end

   fork do
     printf "%-20s start %4d %4d\n", Time.now, $$, task
     sleep rand(5) + 2
     printf "%-20s end   %4d %4d\n", Time.now, $$, task
   end
   count += 1
end

Process.waitall


Kind regards

	robert

-- 
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/