# Multitasking and collecting results

**URL:** <https://www.ruby-forum.com/t/multitasking-and-collecting-results/116552>\
**Category:** Ruby\
**Created:** [October 7, 2007, 7:57am UTC](https://www.ruby-forum.com/t/multitasking-and-collecting-results/116552 "2007-10-07T07:57:44Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![S-gw](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@S-gw](https://www.ruby-forum.com/u/S-gw)\
**Post date:** [October 7, 2007, 7:57am UTC](https://www.ruby-forum.com/t/multitasking-and-collecting-results/116552/1 "2007-10-07T07:57:44Z")

</div>

(new to ruby)

I have a routine that makes a web call then does some work. I need to do  
many of these, and because of latency and all that, I want to go ahead  
and spawn several of these in async “tasks” (trying to avoid key words  
like processes and threads). I need to collect the results of each task.

So, generically, let’s say I have a TaskManager and a Task. TaskManager  
is initialized with an array of elements to process. Each element is  
passed to a Task for processing. I want several Tasks processing in  
parallel, and the result from each Task must get reported back to  
TaskManager.

I see Ruby threads is one way, and despite the disparaging commens I see  
about them, they’re probably fine for me to get started with to figure  
out the “feedback” mechanisms, but eventually I do need a method which  
is capable of leveraging multi-core machines.

Using the pickaxe book Multithreading chapter, I’ve put together this  
little outline, but the results always come back in order when I believe  
useing sleep should randomize them, so I’m suspicioius that I’m not  
really getting async processing out of my code.

#! /usr/local/bin/ruby

class TaskManager

attr\_reader :results

def manageTasks  
taskList = [‘one’, ‘two’, ‘three’]  
threads = []  
@results = []  
indx = 0

```
taskList.each do |taskParam|
  threads[indx] = Thread.new do
    thisTask = Task.new
    @results[indx] = thisTask.doStuff(taskParam)
  end
  indx += 1
end

threads.each {|thred| thred.join}

```

end  
end

class Task  
def doStuff(taskParam)  
pause = ((rand(0.1))\*4)  
sleep pause  
return ('handing back ’ + taskParam + ', ’ + pause.to\_s)  
end  
end

taskMngr = TaskManager.new  
taskMngr.manageTasks  
puts taskMngr.results

Looking for hints as to what I am doing wrong.

Can anyone point me to a tutorial using a technique that will use  
multi-core CPUs?

Many thanks.

– gw

---

<div class="post-metadata">

**Author:** ![S-gw](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@S-gw](https://www.ruby-forum.com/u/S-gw)\
**Post date:** [October 7, 2007, 8:25am UTC](https://www.ruby-forum.com/t/multitasking-and-collecting-results/116552/2 "2007-10-07T08:25:05Z")

</div>

Greg W. wrote:

> I’ve put together this  
> little outline, but the results always come back in order when I believe  
> useing sleep should randomize them, so I’m suspicioius that I’m not  
> really getting async processing out of my code.

Oh wait, they’re in order because that’s the order I have them inserted  
into @results. Duh.

I confirmed async by putting a timer wrapper around the whole thing, and  
indeed it completes in less time than the sum of each task’s pause time.

– gw

---

<div class="post-metadata">

**Author:** ![S-gw](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@S-gw](https://www.ruby-forum.com/u/S-gw)\
**Post date:** [October 7, 2007, 1:31pm UTC](https://www.ruby-forum.com/t/multitasking-and-collecting-results/116552/3 "2007-10-07T13:31:48Z")

</div>

Greg W. wrote:

> Greg W. wrote:
> 
> > I’ve put together this  
> > little outline, but the results always come back in order when I believe  
> > useing sleep should randomize them, so I’m suspicioius that I’m not  
> > really getting async processing out of my code.
> 
> Oh wait, they’re in order because that’s the order I have them inserted  
> into @results. Duh.
> 
> I confirmed async by putting a timer wrapper around the whole thing, and  
> indeed it completes in less time than the sum of each task’s pause time.

Try the following to see some random order in the results. The threads  
in the code enter their data in a  
Queue (located in the ‘thread’ module in the Standard Library). A Queue  
enables you to pass data between threads in a “thread-safe manner”. A  
“thread safe manner” means that only one thread can access the Queue at  
the same time. A Queue guarantees that two threads can’t access the  
Queue at the same time, so the data cannot get scrambled.

require ‘thread’

class TaskManager

attr\_reader :results

def initialize(\*task\_params)  
@task\_params = task\_params  
@results = Queue.new  
end

def start\_producers  
threads = []

```
@task_params.each_with_index do |param, indx|
  threads[indx] = Thread.new do
    @results << Task.new.do_stuff(param)
  end
end

threads.each {|thred| thred.join}

```

end  
end

class Task  
def do\_stuff(x)  
pause = rand() \* 4  
sleep pause

```
"handing back #{x}, #{pause}"

```

end  
end

task\_mngr = TaskManager.new(‘one’, ‘two’, ‘three’)  
task\_mngr.start\_producers  
num\_results = task\_mngr.results.length  
num\_results.times {puts task\_mngr.results.pop}

Note that rand(.1) is the same as rand(), so I don’t know why pickaxe2  
uses rand(.1).

---

<div class="post-metadata">

**Author:** ![S-gw](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@S-gw](https://www.ruby-forum.com/u/S-gw)\
**Post date:** [October 7, 2007, 1:50pm UTC](https://www.ruby-forum.com/t/multitasking-and-collecting-results/116552/4 "2007-10-07T13:50:45Z")

</div>

Greg W. wrote:

> I see Ruby threads is one way, and despite the disparaging commens I see

Ruby threads are a good thing - I wouldn’t disparage them - but beware  
that some Windows versions have broken synchronization primitives.

> Can anyone point me to a tutorial using a technique that will use  
> multi-core CPUs?

Yes, but not using the current Ruby interpreter, which uses a single  
operating-system thread, so cannot parallelize across a multi-core  
system. If you need this with Ruby, you’ll have to look at one of the  
new interpreters.

Clifford H…
