[Home]FeedBack/AsyncMessages

SiarisWiki | FeedBack | RecentChanges | Preferences | Siaris.net

Edit this wiki page to comment on the [Asynchronous Messages] post:

Cool. I'd like to see an example of how to use asynchronous messages. Also check the the latest version of BlankSlate? bundled with my XML builder. The vanila version has a bug in that it is susceptable to methods added to Kernel or Object. Thanks. -- JimWeirich?


Silly me, no example. Here's a simple one:

  require 'async'

  class Show
    def show(it)
      puts "<<#{it.inspect}>>"
    end
  end

  class Foo
    def test(n)
      n.times do 
        yield
        Thread.pass
      end
    end
    def test2(n)
      sleep n
      n
    end
  end

  one = Foo.new
  two = Foo.new
  disp = Show.new

  one.async(:test, 5) {puts "Hello"}
  one.async(:test, 5) {puts "Goodbye"}
  two.async(:test, 5) {puts "Hello2"}

  one.async(:test2, 5).aresult_to(disp, :show)
  one.async(:test2, 2).aresult_to(disp, :show)
  two.async(:test2, 3).aresult_to(disp, :show)

  __END__
Produces:

  Hello
  Hello
  Hello
  Hello2
  Hello
  Hello2
  Hello
  Hello2
  Hello2
  Hello2
  Goodbye
  Goodbye
  Goodbye
  Goodbye
  Goodbye
  <<3>>
  <<5>>
  <<2>>

I hadn't considered methods dynamically added to Kernel or Object after Async was defined ... taking a cue from your builder project I think this addition to Async might do it:

  class Async
    # prevent dynamic ancestor method additions
    self.ancestors.each do |mod|
      next if self == mod
      class << mod
        alias :old_method_added :method_added
        def method_added(id)
          old_method_added(id)
          return unless self == Kernel or self == Object
          Async.hide(id)
        end
      end
    end
    def Async.hide(id)
      undef_method(id)
    end
  end


Hmmm, if someone later includes a utility module to Object, instance methods of the module will be added to Object without triggering a method_added callback. Looks like the KernellessObject? approach below is the only way to ensure an empty proxy. -- AndrewJohnson


Here's an alternate implementation of Async, using the evil.rb's KernellessObject? as the ancestor:
  require 'thread'
  require 'evil'
  Async = Class.new(KernellessObject) do
    def init(&blk)
      @th = Thread.new(&blk)
      @th.abort_on_exception = true
      Kernel.at_exit{@th.join}
    end
    def method_missing(meth,*args, &blk)
      __getobj__.__send__(meth,*args, &blk)
    end
    def __getobj__
      @obj ||= @th.value
    end
    
    # control/status messages
    def awake
      @th.wakeup
      self
    end

    def await
      @th.join
    end

    def aready?
      ! @th.alive?
    end

    def aresult_to(obj,meth)
      thr = Async.new 
      thr.init {obj.send(meth,__getobj__)}
      thr
    end
  end


  class Object
    def async(msg,*args,&blk)
      @async_queue ||= Queue.new
      fut = Async.new 
      fut.init {Thread.stop;self.send(msg,*args,&blk)}
      @async_queue << fut
      @async_thread ||= Thread.new do 
        loop{thr = @async_queue.pop.awake.await;Thread.pass}
      end
      fut
    end
  end
  __END__

Of course, evil.rb defines more than just a KernellessObject? --- more than we might want. (andrew)


SiarisWiki | FeedBack | RecentChanges | Preferences | Siaris.net
This page is read-only | View other revisions
Last edited March 2, 2005 2:58 am by AndrewJohnson (diff)
Search: