Forum: Ruby Asynchronous calls in DRb

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
508bca331a21d64d298561f1079b4113?d=identicon&s=25 Madan Manoharan (Guest)
on 2006-05-18 05:04
(Received via mailing list)
Hello:

I am thinking about writing a distributed application in Ruby where the
application would process all computationally intensive activities in a
'dedicated' server. As I was digging thro' drb/drb.rb, I found the
following:

   def send_message(ref, msg_id, arg, block)  # :nodoc:
      @protocol.send_request(ref, msg_id, arg, block)
      @protocol.recv_reply
<----------- of interest
    end

in the class DRbConn; and


   def main_loop
      Thread.start(@protocol.accept) do |client|
    @grp.add Thread.current
    Thread.current['DRb'] = { 'client' => client ,
                              'server' => self }
    loop do
      begin
        succ = false
        invoke_method = InvokeMethod.new(self, client)
        succ, result = invoke_method.perform
        if !succ && verbose
          p result
          result.backtrace.each do |x|
        puts x
          end
        end
        client.send_reply(succ, result) rescue nil
<----------- of interest
      ensure
        unless succ
          client.close
          break
        end
      end
    end
      end
    end
  end

in the class DRbServer.

Clearly, DRb is synchronous. This would mean that my 'client' cannot
hand
off the job to the 'server' and do other things when the 'server' is
doing
the computationally intensive job (parallel execution of the 'client'
and
'server' is not possible as the 'client' will be blocked waiting for
reply
from the 'server').

My questions are:
(1) Is there a way for me to make asynchronous calls in DRb; in other
words,
am I overlooking that functionality?
(2) If there is no asynchronous call capabilities in DRb, why was that
not
added when it could have been easily done (not call client.send_reply
and
recv_reply)? Is there a technical reason for it?

Any help will be greatly appreciated.

Thanks,
Madan.
58479f76374a3ba3c69b9804163f39f4?d=identicon&s=25 Eric Hodel (Guest)
on 2006-05-18 05:38
(Received via mailing list)
On May 17, 2006, at 8:03 PM, Madan Manoharan wrote:

> I am thinking about writing a distributed application in Ruby where
> the
> application would process all computationally intensive activities
> in a
> 'dedicated' server. As I was digging thro' drb/drb.rb, I found the
> following:

[...]

> Clearly, DRb is synchronous.

Throw away your magnifying glass, you're looking too hard.

DRb and Ruby work the same way.  In both method calls are
synchronous.  This does not prevent you from writing a library that
works asynchronously.

> This would mean that my 'client' cannot hand off the job to the
> 'server' and do other things when the 'server' is doing the
> computationally intensive job (parallel execution of the 'client'
> and 'server' is not possible as the 'client' will be blocked
> waiting for reply from the 'server').

Sure it can.  I do this all the time without DRb so I can do it just
as easily with DRb.  Method dispatch works the same with or without DRb.

> My questions are:
> (1) Is there a way for me to make asynchronous calls in DRb; in
> other words,
> am I overlooking that functionality?

The easiest way is to use threads.  The next easiest way is to write
an asynchronous library without DRb then modify it to use DRb.

> (2) If there is no asynchronous call capabilities in DRb, why was
> that not
> added when it could have been easily done (not call
> client.send_reply and
> recv_reply)? Is there a technical reason for it?

There's no reason to have asynchronous calls.  Asynchronous libraries
are implemented above the level of method dispatch.

--
Eric Hodel - drbrain@segment7.net - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com
B44ab09b79ee4a0cc4b4ca69e10eeb3a?d=identicon&s=25 Brian Mitchell (Guest)
on 2006-05-18 06:20
(Received via mailing list)
On 5/17/06, Madan Manoharan <madan.manoharan@gmail.com> wrote:
> (1) Is there a way for me to make asynchronous calls in DRb; in other words,
> am I overlooking that functionality?

Yes. It is actually more simple that you think (Ruby is more magic
that most realize). The key is that it doesn't need to be in DRb. The
first thing I thought of when I saw async. + DRb in the title was a
language called Io [1]. It is interesting in many ways (though under
heavy work still). There is one point of interest that is useful in
this case. Io supports something called Futures and also plain
asynchronous calls:

obj := Object clone do (foo := method("Hello" println))

obj foo #=> both print and return "Hello"

obj @foo #=> print "Hello" when forced or when the scheduler activates
it and return a Future representing the return value (or exception)

obj @@foo #=> same as @foo but w/o a return value (get nil back in in
call failure).

I should also note another mechanism not in Io [2] that is very
similar to futures. Promises provide the same feature as a future but
will only execute when the value is used (i.e. a forced block) while
the typical notion of a future is something that will eventually
happen on its own.

Ruby does not have any of these in the standard library BUT they can
easily be built (and have -- use google or check out some of
MenTaLguY's work on this topic). The key is to keep the mechanism
transparent or at least clean. Io can manage something that might as
well be transparent to most people (some exceptions but even those are
few and out of scope here). Ruby can't be quite as nice [3]. That is a
far cry from defeat though. Of course if should mention that async.
calls w/o significant return values is easy to make clean.

The key feature of the implementation would have to be the use of
threads since Ruby already uses select() internally (maybe in the
future it will use libevent to boost performance). Again, some work
has been done in related areas. I would highly recommend you check it
out.

> (2) If there is no asynchronous call capabilities in DRb, why was that not
> added when it could have been easily done (not call client.send_reply and
> recv_reply)? Is there a technical reason for it?

There are so many things we could add to DRb. The problem is that
negates one of DRb's strengths: simplicity. Adding things that aren't
a required part of DRb is overload. However, _if_ your requirements
are *simple* maybe there could be a simple plugin that could be used
with a quick and simple optional require. My personal feeling is that
DRb could probably shed some of its current weight [4] and focus a
little more on a clean way people can plug and play customizations of
their own [5].

Brian.

[1] http://iolanguage.com/
[2] Yet. It is a very simple patch to its "prelude" code as I call it.
Maybe I will submit one once I get my dev. laptop back from repair
(has all my Io work on it unfortunately).
[3] No Object#become or the like -- evil.rb provides this but it still
won't work on immediates. Proxy objects or explicit value retrieval
(like you see in Java's concurrency interfaces and Ruby threads) would
probably the main candidates.
[4] The only thing that is weighty to me is that is ACLs. There might
be a better way to factor that out and provide a more complete and
generic ACL library. Of course this is only me speaking. I am sure
there are those that use DRb ACLs all the time.
[5] My more general rant is that we shouldn't try to change the
standard library to a all feature circus. I think there is reason to
be potent but not bloated.
288733e11db1c6dbbf50871d2c6738c6?d=identicon&s=25 Uncutstone Wu (uncutstone)
on 2006-05-18 07:37
Eric Hodel wrote:
> The easiest way is to use threads.  The next easiest way is to write
> an asynchronous library without DRb then modify it to use DRb.
>
Yes, it is quite easy to implement asynchronous call using thread. Here
is the code.

class AsyncHello
  def asyncHello(arg)
    puts "hello called, arg is #{arg}"
    Thread.new(arg) {|arg|  #trick: how to implement asynchronous call
using thread
      hello(arg)
    }
  end
  def hello(arg)
    sleep 5
    puts "Hello #{arg}"
  end
end

def testasyncall
  o = AsyncHello.new
  o.asyncHello("John")
  puts "This should be displayed before hello john"
  sleep(10)
end

testasyncall

result:
hello called, arg is John
This should be displayed before hello john
Hello John


Best regards.

uncutstone
508bca331a21d64d298561f1079b4113?d=identicon&s=25 Madan Manoharan (Guest)
on 2006-05-19 15:37
(Received via mailing list)
Thank you all. As was suggested, I wrote a async lib using threads.

-Madan.
This topic is locked and can not be replied to.