[MacRuby-devel] tentative first steps with GCD in macruby
John Shea
johnmacshea at gmail.com
Tue Oct 20 10:11:39 PDT 2009
Dear All,
(sorry for the long post)
I have been experimenting a bit with GCD in MacRuby 0.5 beta.
I have managed to get some code working as I would expect it to work,
and I am wondering if a few of you could provide a sanity check that
everything i am doing is above board and not the result of unspecified
behaviour.
My main concern is that when running a set of tasks and collecting the
results that the collecting itself is not thread safe (in this case
the << operator). And if it is not thread safe - then what is the best
way to collect results from dispatched tasks.
But so far it seems to work magically well.
Before I put the code down - here are some initial discoveries (which
may have been obvious to everyone else).
1. When running tests you need wait until the threads are finished -
otherwise the main loop will finish before the output comes back from
other threads.
I did that with a sleep, but also experimented with looping until an
array is filled.
2. Scope: Given one of the global system queues :
gcdq = Dispatch::Queue.concurrent(:default)
and looping over a number of dispatches:
5.times do |index|
gcdq.dispatch {puts index}
end
the task dispatched will hold the last value of index - it will not
capture the changing value of index - I assume that the task has a
pointer directly to the index variable.
(an article by Bill Bumgarner http://www.friday.com/bbum/2009/08/29/blocks-tips-tricks/
pointed out something similar in objC - but had a different way of
solving this)
So to capture that changing index, I created a Proc then turned it
back to a block, eg:
5.times do |index|
task = Proc.new {puts index}
gcdq.dispatch &task
end
3. You will notice that in the code below in check = a.run-disp2 that
the array is returned - I assume empty - and is gradually filled by
the tasks.
class A
def run_disp(an_array)
gcdq = Dispatch::Queue.concurrent(:default)
["f","g","h","i", "j"].each_with_index do |val, index|
task = Proc.new {an_array << do_something(val, index)}
gcdq.dispatch &task
puts "Loaded #{index}"
end
end
def run_disp2
an_array = []
gcdq = Dispatch::Queue.concurrent(:default)
["f","g","h","i", "j"].each_with_index do |val, index|
task = Proc.new {an_array << do_something(val, index)}
gcdq.dispatch &task
puts "Loaded #{index}"
end
an_array
end
def do_something(val, index)
#staggered sleeps so as to prove that various tasks finish first
result = val * (index + 1)
case index
when 0, 1
sleep 2
when 2
sleep 1
else
sleep 0
end
puts "yeah baby! #{index}"
result
end
end
a = A.new
#pass array to be filled
an_array = []
a.run_disp(an_array)
sleep 10
puts "passed array: #{an_array.join(", ")}"
check = a.run_disp2
sleep 10
puts "returned array: #{check.join(", ")}"
#results:
# Loaded 0
# Loaded 1
# Loaded 2
# Loaded 3
# Loaded 4
# yeah baby! 4yeah baby! 3
#
# yeah baby! 2
# yeah baby! 1
# yeah baby! 0
# passed array: iiii, jjjjj, hhh, gg, f
# Loaded 0
# Loaded 1
# Loaded 2
# Loaded 3
# Loaded 4
# yeah baby! 3
# yeah baby! 4
# yeah baby! 2
# yeah baby! 0
# yeah baby! 1
# returned array: iiii, jjjjj, hhh, f, gg
#assume puts is not transactional.
thanks in advance for any comments / corrections,
John
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-devel/attachments/20091020/73d586f2/attachment-0001.html>
More information about the MacRuby-devel
mailing list