[MacRuby] #597: Dispatch Queue async method inconsistent results
#597: Dispatch Queue async method inconsistent results --------------------------------------+------------------------------------- Reporter: Knut.Olaf.Lien@… | Owner: lsansonetti@… Type: defect | Status: new Priority: blocker | Milestone: Component: MacRuby | Keywords: GCD async method --------------------------------------+------------------------------------- Trying to run this: ## Fibionti example showing Grand Central Dispatch in action ## using MacRuby ## Feb. 2, 2010 def fib(n=1) if n < 3 1 else fib(n-1) + fib(n-2) end end q = Dispatch::Queue.concurrent grp = Dispatch::Group.new result = [] 8.times do |index| q.async(grp) do result[index] = fib(ARGV[0].to_i) end end ## Wait for the result to be calculated and print the results grp.wait puts result Gives inconsistent fibionati results, i.e. some of the values become false instead of the correct fibionati number. No clue if this is a bug or just my implementation is wrong. -- Ticket URL: <http://www.macruby.org/trac/ticket/597> MacRuby <http://macruby.org/>
#597: Dispatch Queue async method inconsistent results --------------------------------------+------------------------------------- Reporter: Knut.Olaf.Lien@… | Owner: ernest.prabhakar@… Type: defect | Status: new Priority: blocker | Milestone: Component: MacRuby | Keywords: GCD async method --------------------------------------+------------------------------------- Changes (by ernest.prabhakar@…): * owner: lsansonetti@… => ernest.prabhakar@… -- Ticket URL: <http://www.macruby.org/trac/ticket/597#comment:1> MacRuby <http://macruby.org/>
#597: Dispatch Queue async method inconsistent results --------------------------------------+------------------------------------- Reporter: Knut.Olaf.Lien@… | Owner: ernest.prabhakar@… Type: defect | Status: new Priority: blocker | Milestone: Component: MacRuby | Keywords: GCD async method --------------------------------------+------------------------------------- Comment(by ernest.prabhakar@…): Well, it works for q.sync, which is a good sign: 8.times {|i| q.sync {result[i] = fib(i)}} And it works for me (on the latest trunk) with q.async: 8.times {|i| q.async {result[i] = fib(i)}} q.sync {} But, I do get odd behavior with async(grp). 8.times {|i| q.async(grp) {result[i] = fib(i)}} grp.wait p result => [nil, 1, 1, 2, 3, 5, 8, 13] Hmm. -- Ticket URL: <http://www.macruby.org/trac/ticket/597#comment:2> MacRuby <http://macruby.org/>
#597: Dispatch Queue async method inconsistent results --------------------------------------+------------------------------------- Reporter: Knut.Olaf.Lien@… | Owner: ernest.prabhakar@… Type: defect | Status: closed Priority: blocker | Milestone: Component: MacRuby | Resolution: invalid Keywords: GCD async method | --------------------------------------+------------------------------------- Changes (by ernest.prabhakar@…): * status: new => closed * resolution: => invalid Comment: I even get it with no function at all. => [0, 1, 2, 3, false, 5] Oh, wait, you're using a *local* variable. You need to use a block variable, I think: @result = []; 8.times {|i| q.async(grp) {@result[i] = i}} p @result => [0, 1, 2, 3, 4, 5, 6, 7] Using a copy of the array "sometimes" works, but I'm not quite sure how or why. Still, the technical answer is that attempting to modify a dynamic object inside a GCD leads to "undefined" behavior, so I'll mark this as "behaves correctly". :-/ -- Ticket URL: <http://www.macruby.org/trac/ticket/597#comment:3> MacRuby <http://macruby.org/>
On Feb 3, 2010, at 10:13 AM, MacRuby wrote:
Using a copy of the array "sometimes" works, but I'm not quite sure how or why. Still, the technical answer is that attempting to modify a dynamic object inside a GCD leads to "undefined" behavior, so I'll mark this as "behaves correctly". :-/
I think this is going to be a perennial problem until we figure out some idiom for accessing variables from within GCD code (preferably something terse which can be easily taught, in the vein of @synchronized). Ruby programmers are just too used to having a GIL pay for their sins. :-( - Jordan
Hi Jordan, On Feb 3, 2010, at 12:43 PM, Jordan K. Hubbard wrote:
On Feb 3, 2010, at 10:13 AM, MacRuby wrote:
Using a copy of the array "sometimes" works, but I'm not quite sure how or why. Still, the technical answer is that attempting to modify a dynamic object inside a GCD leads to "undefined" behavior, so I'll mark this as "behaves correctly". :-/
I think this is going to be a perennial problem until we figure out some idiom for accessing variables from within GCD code (preferably something terse which can be easily taught, in the vein of @synchronized). Ruby programmers are just too used to having a GIL pay for their sins. :-(
Haven't you been paying attention to trunk? :-) http://svn.macosforge.org/repository/ruby/MacRuby/trunk/lib/dispatch/dispatc... # Wrap the passed +obj+ (or its instance) inside an Actor to serialize access # and allow asynchronous invocation plus a callback def wrap(obj) Dispatch::Actor.new( (obj.is_a? Class) ? obj.new : obj) end http://svn.macosforge.org/repository/ruby/MacRuby/trunk/lib/dispatch/actor.r... i.e., ----- require 'dispatch' serialized_array = Dispatch.wrap(Array) ---- Would that do it for you? -- Ernie P.
On Feb 3, 2010, at 2:47 PM, Ernest N. Prabhakar, Ph.D. wrote:
require 'dispatch'
serialized_array = Dispatch.wrap(Array)
Would that do it for you?
Given that this works for any object, yes! That's perfect! Thanks, - Jordan
#597: Dispatch Queue async method inconsistent results --------------------------------------+------------------------------------- Reporter: Knut.Olaf.Lien@… | Owner: ernest.prabhakar@… Type: defect | Status: closed Priority: blocker | Milestone: Component: MacRuby | Resolution: invalid Keywords: GCD async method | --------------------------------------+------------------------------------- Comment(by lsansonetti@…): Ernie's diagnosis is wrong. The problem here is that the program is accessing the result variable concurrently. Accesses must be synchronized by using a serial queue. The following should work (untested) {{{ def fib(n=1) if n < 3 1 else fib(n-1) + fib(n-2) end end q = Dispatch::Queue.concurrent grp = Dispatch::Group.new syncq = Dispatch::Queue.new('sync') result = [] 8.times do |index| q.async(grp) do res = fib(ARGV[0].to_i) syncq.sync { result[index] = res } end end }}} -- Ticket URL: <http://www.macruby.org/trac/ticket/597#comment:4> MacRuby <http://macruby.org/>
#597: Dispatch Queue async method inconsistent results --------------------------------------+------------------------------------- Reporter: Knut.Olaf.Lien@… | Owner: ernest.prabhakar@… Type: defect | Status: closed Priority: blocker | Milestone: Component: MacRuby | Resolution: invalid Keywords: GCD async method | --------------------------------------+------------------------------------- Comment(by Knut.Olaf.Lien@…): OK, thanks for the heads up. Much to learn about concurrent implementation. Exciting stuff... -- Ticket URL: <http://www.macruby.org/trac/ticket/597#comment:5> MacRuby <http://macruby.org/>
participants (3)
-
Ernest N. Prabhakar, Ph.D.
-
Jordan K. Hubbard
-
MacRuby