[MacRuby] #476: GCD Groups should be a wrapper around dispatch, not its own invocation style
#476: GCD Groups should be a wrapper around dispatch, not its own invocation style ----------------------------------------+----------------------------------- Reporter: ernest.prabhakar@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: blocker | Milestone: MacRuby 0.5 Component: MacRuby | Keywords: gcd ----------------------------------------+----------------------------------- Right now, GCD Groups are treated almost like a Queue, so developers call dispatch on them -- except that: - you need to specify a queue as a parameter -- or use (atypically) have it invisibly invoke the default queue - there's no way to specify synchronous dispatch This works well if you really just want async concurrency, but becomes awkward (and IMHO confusing) for anything else. g = Dispatch::Group.new g.dispatch {work_function(i)}} g.dispatch(q_a) {work_function(i)}} g.dispatch(q_b, false) {work_function(i)}} g.wait I don't know if it is possible, but what I'd prefer is for Groups to take a block *containing* multiple dispatch invocations, and auto-magically associate them with a group. So for example, you could do: g = Dispatch::Group.new g.wait do q_a.dispatch(true) {work_function(i)} q_b.dispatch(false) {work_function(i)} end In this case, the "group" is synchronous so it automatically does a wait until the "child" dispatches complete. For async behavior, simply do: g.on_completion { puts "I'm all done" } g.notify do q_a.dispatch {work_function(i)} q_b.dispatch {work_function(i)} end If you want to add some invocations to the group but neither wait or notify yet, use a "shovel" to add them: g << { q_c.dispatch {work_function(i)} } As a bonus, one could provide a convenience class method for the synchronous case that avoids the need for any variable at all: Dispatch::Group.wait do q_a.dispatch(true) {work_function(i)} q_b.dispatch(false) {work_function(i)} end While this does require you to be more explicit in the concurrency async case, I think this API better reflects the full semantics of GCD groups. Of course, this presumes that queue dispatches would need to check if they're executing inside a group; I'm sure that must be possible, but I don't know what the performance implications might be. Still, I wanted to raise it now before 0.5 is final and people start relying on the current API. -- Ticket URL: <http://www.macruby.org/trac/ticket/476> MacRuby <http://macruby.org/>
#476: GCD Groups should be a wrapper around dispatch, not its own invocation style ----------------------------------------+----------------------------------- Reporter: ernest.prabhakar@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: blocker | Milestone: MacRuby 0.5 Component: MacRuby | Keywords: gcd ----------------------------------------+----------------------------------- Comment(by ernest.prabhakar@…): Here's an alternative proposal that would probably be simpler to implement: group.for_queue(q).dispatch(sync) { block } That is, group.dispatch would take a 'sync' parameter, just like queue.dispatch. The default would be the default queue, but the group would have an ivar representing the "current' queue. This provides consistency while avoiding the need to always specify the sync to define a queue. Of course, the syntax is ugly, but this allows us to define a convenience method on queue: queue.for(group).dispatch(sync) { block } That seems the most consistent with how dispatch works outside of groups, and semantically cleaner. Thoughts? -- Ticket URL: <http://www.macruby.org/trac/ticket/476#comment:1> MacRuby <http://macruby.org/>
#476: GCD Groups should be a wrapper around dispatch, not its own invocation style ----------------------------------------+----------------------------------- Reporter: ernest.prabhakar@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: blocker | Milestone: MacRuby 0.5 Component: MacRuby | Keywords: gcd ----------------------------------------+----------------------------------- Comment(by joshua.ballanco@…): Ideally, I'd prefer a change such that the programmer doesn't need to worry about the difference between a dispatch group and a dispatch queue. There would be only one "Dispatch" class with methods "sync", "async", "apply", etc. Dispatch.sync would take a name parameter (a symbol?), and subsequent calls to Dispatch.sync with the same parameter would dispatch to the same queue. Dispatch.async would just take an optional priority parameter. Dispatch.apply would iterate over a collection. All would return a group which could be optionally captured for later calls to wait, and would accept an optional group argument to add a block to a pre- existing group. So, for example: {{{ notifications = Dispatch.async do send_start_notification end url_fetching = Dispatch.apply(LIST_OF_URLS) do |url| connection = open(url) Dispatch.sync(:disk_dispatch) do File.open(URL_FILE) { |f| f << connection.read } end end url_fetching.wait Dispatch.async(:group => notifications) do send_finish_notification end do_other_work notifications.wait exit }}} -- Ticket URL: <http://www.macruby.org/trac/ticket/476#comment:2> MacRuby <http://macruby.org/>
#476: GCD Groups should be a wrapper around dispatch, not its own invocation style ----------------------------------------+----------------------------------- Reporter: ernest.prabhakar@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: blocker | Milestone: MacRuby 0.5 Component: MacRuby | Keywords: gcd ----------------------------------------+----------------------------------- Comment(by ernest.prabhakar@…): I'm not sure I'd want to go that far, but I like the idea of passing groups -- and even sync -- as named parameters to dispatch (i.e., a hash) g = Dispatch::Group.new q1.dispatch(group: g) { block } q2.dispatch(group: g, sync:true) { block } g.wait That would seem both the simplest to implement, and the clearest semantically. I'll file a bug about the 'sync' keyword... -- Ticket URL: <http://www.macruby.org/trac/ticket/476#comment:3> MacRuby <http://macruby.org/>
#476: GCD Groups should be a wrapper around dispatch, not its own invocation style ----------------------------------------+----------------------------------- Reporter: ernest.prabhakar@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: blocker | Milestone: MacRuby 0.5 Component: MacRuby | Keywords: gcd ----------------------------------------+----------------------------------- Comment(by ernest.prabhakar@…): NOTE: group dispatch is ALWAYS aysnc; my bad -- Ticket URL: <http://www.macruby.org/trac/ticket/476#comment:4> MacRuby <http://macruby.org/>
#476: GCD Groups should be a wrapper around dispatch, not its own invocation style ----------------------------------------+----------------------------------- Reporter: ernest.prabhakar@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: blocker | Milestone: MacRuby 0.5 Component: MacRuby | Keywords: gcd ----------------------------------------+----------------------------------- Comment(by ernest.prabhakar@…): PROPOSAL:: q.apply q.sync() q.async() q.async(group) -- Ticket URL: <http://www.macruby.org/trac/ticket/476#comment:5> MacRuby <http://macruby.org/>
#476: GCD Groups should be a wrapper around dispatch, not its own invocation style ----------------------------------------+----------------------------------- Reporter: ernest.prabhakar@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: blocker | Milestone: MacRuby 0.5 Component: MacRuby | Keywords: gcd ----------------------------------------+----------------------------------- Comment(by ernest.prabhakar@…): PROPOSAL: queue.dispatch and group.dispatch -- Ticket URL: <http://www.macruby.org/trac/ticket/476#comment:6> MacRuby <http://macruby.org/>
#476: GCD Groups should be a wrapper around dispatch, not its own invocation style ----------------------------------------+----------------------------------- Reporter: ernest.prabhakar@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: blocker | Milestone: MacRuby 0.5 Component: MacRuby | Keywords: gcd ----------------------------------------+----------------------------------- Comment(by ernest.prabhakar@…): PROPOSAL: delete queue.dispatch and group.dispatch -- Ticket URL: <http://www.macruby.org/trac/ticket/476#comment:7> MacRuby <http://macruby.org/>
#476: GCD Groups should be a wrapper around dispatch, not its own invocation style ----------------------------------------+----------------------------------- Reporter: ernest.prabhakar@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: blocker | Milestone: MacRuby 0.5 Component: MacRuby | Keywords: gcd ----------------------------------------+----------------------------------- Comment(by conradwt@…): After reading through the specification, I would like to see the following more explicit API: {{{ queue = Dispatch::Queue.new( "comp.lang.MyCustomerQueue", attribute = nil ) queue.dispatch_async( &block ) queue.dispatch_sync( &block ) queue.dispatch_apply( iterations, &block ) group = Dispatch::Group.new group.dispatch_async( queue, &block ) group.dispatch_wait( Dispatch::TIME_FOREVER ) group.dispatch_release }}} These are just some of my thoughts because I was looking for something that was inline with the C API. Also, the explicit API eliminates the need for 'if' constructs within the function definition within 'gcd.c'. Next, we can namespace this by adding both the Group and Queue classes within the module Dispatch. -- Ticket URL: <http://www.macruby.org/trac/ticket/476#comment:8> MacRuby <http://macruby.org/>
#476: GCD Groups should be a wrapper around dispatch, not its own invocation style ----------------------------------------+----------------------------------- Reporter: ernest.prabhakar@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: blocker | Milestone: MacRuby 0.5 Component: MacRuby | Keywords: gcd ----------------------------------------+----------------------------------- Comment(by conradwt@…): Here's a better representation and it's associated usage: API: {{{ module Dispatch # constants... TIME_FOREVER = 1 class Queue def initialize( label, attribute = nil ) @label = label @attribute = attribute end def dispatch_async( &block ) end def dispatch_sync( &block ) end def dispatch_apply( iterations, &block ) end end class Group def dispatch_async( queue, &block ) end def dispatch_wait( timeout ) end def dispatch_release end end end }}} USAGE: {{{ block = lambda { do_some_work } queue = Dispatch::Queue.new( "comp.lang.MyCustomerQueue" ) queue.dispatch_async( &block ) queue.dispatch_sync( &block ) queue.dispatch_apply( 5, &block ) group = Dispatch::Group.new group.dispatch_async( queue, &block ) group.dispatch_wait( Dispatch::TIME_FOREVER ) group.dispatch_release }}} -- Ticket URL: <http://www.macruby.org/trac/ticket/476#comment:9> MacRuby <http://macruby.org/>
#476: GCD Groups should be a wrapper around dispatch, not its own invocation style ----------------------------------------+----------------------------------- Reporter: ernest.prabhakar@… | Owner: lsansonetti@… Type: enhancement | Status: closed Priority: blocker | Milestone: MacRuby 0.5 Component: MacRuby | Resolution: fixed Keywords: gcd | ----------------------------------------+----------------------------------- Changes (by lsansonetti@…): * status: new => closed * resolution: => fixed Comment: Proposal implemented as r3086. Conrad: we opted for a similar design. You now have the following methods on Queue: #sync, #async (which can accept an optional Group argument), #apply. -- Ticket URL: <http://www.macruby.org/trac/ticket/476#comment:10> MacRuby <http://macruby.org/>
participants (1)
-
MacRuby