Passing parameter to actors

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Passing parameter to actors

Bob Brown
Maybe this is a faq...apologies if so.

Let's say I have an array of actors representing a pipeline such that
actor[i] should send() to actor[I + 1].

For this to work, I need to tell each actor what value of i it is being
instantiated against.

Currently, I am creating a new class Intermediary extends DefaultPooledActor
and then doing:

    for (i in 1..30) {
      intermediaries << new Intermediary(i: i, next: { int index ->
intermediaries[index + 1] })
    }

Strikes me that instead of messing around declaring classes, I should be
able to do something like:

    for (i in 1..30) {
      intermediaries << actor(index: i) { index -> intermediaries[index  +
1].send('message')  })
    }

What am I missing?

Cheers,

BOB


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Passing parameter to actors

Dierk König
> ..
>      intermediaries << actor(index: i) { index -> intermediaries[index  +
..

Well, the actor method doesn't take a map argument.

If I understand you requirements correctly, your first version looks good.

An alternative would be to start with an actor the creates a new
one for the next index within its act method. That would be
a very functional programming style.

Third, you could use the Groovy feature that closures bind over local
vars and make a creator-method that returns your closure

def makeClosure(int i) {
        return { println i }
}
def cl = makeClosure(12)
cl()

or even shorter, use a prototype closure and curry your index

def proto = { i -> println i }
def actual = proto.curry(12)
actual()

cheers
Dierk

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Passing parameter to actors

Vaclav
Administrator
The Dierk's idea of currying could be implemented perhaps this way:

import groovyx.gpars.actor.Actors

def intermediaries = []

for (i in 1..30) {
    intermediaries << Actors.actor({index ->
        println('Received: ' + index + ":" + receive())
        if (index != 29) intermediaries[index + 1].send('message')
    }.curry(i))
}

intermediaries[0].send 'message'


Vaclav




On Sat, Feb 27, 2010 at 6:10 PM, Dierk König <[hidden email]> wrote:
> ..
>      intermediaries << actor(index: i) { index -> intermediaries[index  +
..

Well, the actor method doesn't take a map argument.

If I understand you requirements correctly, your first version looks good.

An alternative would be to start with an actor the creates a new
one for the next index within its act method. That would be
a very functional programming style.

Third, you could use the Groovy feature that closures bind over local
vars and make a creator-method that returns your closure

def makeClosure(int i) {
       return { println i }
}
def cl = makeClosure(12)
cl()

or even shorter, use a prototype closure and curry your index

def proto = { i -> println i }
def actual = proto.curry(12)
actual()

cheers
Dierk

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email





--
E-mail: [hidden email]
Blog: http://www.jroller.com/vaclav
Linkedin page: http://www.linkedin.com/in/vaclavpech
Reply | Threaded
Open this post in threaded view
|

RE: Passing parameter to actors

Bob Brown
Thanks, guys.

For interest's sake, this is what I have...it's a really trivial pipeline:

///
import groovyx.gpars.actor.*

final intermediaries = []

def src = Actors.actor {index ->
  println "Source: Starting..."
  react { go ->
    println "Source: got '$go'; sending 'hello'.."
    println "Source: got '${intermediaries[1].sendAndWait('hello')}'"
    }
}

intermediaries << src

for (i in 1..3) {
  intermediaries << Actors.actor({index ->
    println "Intermediary[$index]: Starting..."

    react { msg ->
      println("Intermediary[$index]: Received: '$msg'")
      reply intermediaries[index + 1].sendAndWait("${msg}[$index]")
    }
  }.curry(i))

}

intermediaries << Actors.actor {
  println "Sink: Starting..."
  react { msg ->
    println "Sink: got '$msg'"
    reply "thanks"
  }
}

src << 'go'
 
"OK"
///

A question and an observation:

Q:
I have tried to use sendAndWait with a timeout:

reply intermediaries[index + 1].sendAndWait(10.seconds, "${msg}[$index]")

This just gives an exception:

groovy.lang.MissingPropertyException: No such property: seconds for class:
java.lang.Integer

I'm missing an import? Couldn't figure out what...

Obs:

Instead of code like:

def resp =  theActor.sendAndWait(msg)
println "Got $resp"
reply resp

I think I'd like to be able to do something like:

theActor.sendAndWait(msg) { resp ->
  println "Got $resp from ${resp.sender}"
  reply resp
}

Would this be a worthwhile enhancement?

Or maybe the syntax could be:

theActor.sendAndWait(msg).withResponse { resp ->
  println "Got $resp from ${resp.sender}"
  reply resp
}

Cheers,

BOB

> -----Original Message-----
> From: Vaclav Pech [mailto:[hidden email]]
> Sent: Sunday, 28 February 2010 4:27 AM
> To: [hidden email]
> Subject: Re: [gpars-user] Passing parameter to actors
>
> The Dierk's idea of currying could be implemented perhaps this way:
>
> import groovyx.gpars.actor.Actors
>
> def intermediaries = []
>
> for (i in 1..30) {
>     intermediaries << Actors.actor({index ->
>         println('Received: ' + index + ":" + receive())
>         if (index != 29) intermediaries[index + 1].send('message')
>     }.curry(i))
> }
>
> intermediaries[0].send 'message'
>
>
> Vaclav
>
>
>
>
>
> On Sat, Feb 27, 2010 at 6:10 PM, Dierk König <[hidden email]>
> wrote:
>
>
> > ..
>
> >      intermediaries << actor(index: i) { index ->
intermediaries[index

> +
>
> ..
>
> Well, the actor method doesn't take a map argument.
>
> If I understand you requirements correctly, your first version looks
> good.
>
> An alternative would be to start with an actor the creates a new
> one for the next index within its act method. That would be
> a very functional programming style.
>
> Third, you could use the Groovy feature that closures bind over
local

> vars and make a creator-method that returns your closure
>
> def makeClosure(int i) {
>       return { println i }
> }
> def cl = makeClosure(12)
> cl()
>
> or even shorter, use a prototype closure and curry your index
>
> def proto = { i -> println i }
> def actual = proto.curry(12)
> actual()
>
> cheers
> Dierk
>
>
>
---------------------------------------------------------------------

> To unsubscribe from this list, please visit:
>
>   http://xircles.codehaus.org/manage_email
>
>
>
>
>
>
>
> --
> E-mail: [hidden email]
> Blog: http://www.jroller.com/vaclav
> Linkedin page: http://www.linkedin.com/in/vaclavpech



---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

RE: Passing parameter to actors

Bob Brown
 

> def resp =  theActor.sendAndWait(msg)
> println "Got $resp"
> reply resp
>
> I think I'd like to be able to do something like:
>
> theActor.sendAndWait(msg) { resp ->
>   println "Got $resp from ${resp.sender}"
>   reply resp
> }
>
> Would this be a worthwhile enhancement?
>
> Or maybe the syntax could be:
>
> theActor.sendAndWait(msg).withResponse { resp ->
>   println "Got $resp from ${resp.sender}"
>   reply resp
> }

Got to thinking:

theActor.sendAndReact(msg) { resp ->
  println "Got $resp from ${resp.sender}"
  reply resp
}

The name sendAndReact might be more in keeping with the 'ethos'  than
sendAndWait...?

BOB


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Passing parameter to actors

Vaclav
Administrator
In reply to this post by Bob Brown
Hi Bob,

thanks for sharing your code. You're doing interesting experiments.
Please, see the inlined comments:


Q:
I have tried to use sendAndWait with a timeout:

reply intermediaries[index + 1].sendAndWait(10.seconds, "${msg}[$index]")

This just gives an exception:

groovy.lang.MissingPropertyException: No such property: seconds for class:
java.lang.Integer

I'm missing an import? Couldn't figure out what...

You need to wrap the code in "use(TimeCategory)" to enable TimeCategory DSL, otherwise there's always the option to use the "sendAndWait(final T message, final long timeout, final TimeUnit units)" method.

Obs:

Instead of code like:

def resp =  theActor.sendAndWait(msg)
println "Got $resp"
reply resp

I think I'd like to be able to do something like:

theActor.sendAndWait(msg) { resp ->
 println "Got $resp from ${resp.sender}"
 reply resp
}

Would this be a worthwhile enhancement?

I guess the sendAndContinue() method is what you're looking for here. Although, the reply() method would have to be invoked slightly differently, since plain "reply resp" would reply to the "resp" message, not the original "msg" message.

def sender = msg.sender
theActor.sendAndContinue(msg) {resp ->
    println ...
    sender << resp
}
 
Cheers,

Vaclav


Reply | Threaded
Open this post in threaded view
|

RE: Passing parameter to actors

Bob Brown
> thanks for sharing your code. You're doing interesting experiments.

Note sure if it's interesting, but *I'm* learning.

> Please, see the inlined comments:
>
>
>
>
> Q:
> I have tried to use sendAndWait with a timeout:
>
> reply intermediaries[index + 1].sendAndWait(10.seconds,
> "${msg}[$index]")
>
> This just gives an exception:
>
> groovy.lang.MissingPropertyException: No such property: seconds
> for class:
> java.lang.Integer
>
> I'm missing an import? Couldn't figure out what...
>
>
>
> You need to wrap the code in "use(TimeCategory)" to enable TimeCategory
> DSL, otherwise there's always the option to use the "sendAndWait(final T
> message, final long timeout, final TimeUnit units)" method.

OK. I wasn't sure whether GPars was supposed to be doing this on my
behalf...the doco wasn't quite clear enough on this (IMHO, sorry).

>
>
> Obs:
>
> Instead of code like:
>
> def resp =  theActor.sendAndWait(msg)
> println "Got $resp"
> reply resp
>
> I think I'd like to be able to do something like:
>
> theActor.sendAndWait(msg) { resp ->
> println "Got $resp from ${resp.sender}"
> reply resp
> }
>
> Would this be a worthwhile enhancement?
>
>
>
> I guess the sendAndContinue() method is what you're looking for here.
> Although, the reply() method would have to be invoked slightly
differently,
> since plain "reply resp" would reply to the "resp" message, not the
original
> "msg" message.
>
> def sender = msg.sender
> theActor.sendAndContinue(msg) {resp ->
>     println ...
>     sender << resp
> }

Not really, in this case. Since sendAndContinue is non-blocking. It "allows
the caller to continue its processing while the supplied closure is waiting
for a reply from the actor." I was trying to suggest a (to me) more natural
syntax for the blocking (w.r.t. the caller) behaviour.

Actually, I wonder if 'sendAndReact' might be better naming (it isn't just
waiting, but also processing as react would):

theActor.sendAndReact(msg) { resp ->
  println "Got $resp from ${resp.sender}"
  reply resp
}

BOB


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Passing parameter to actors

Vaclav
Administrator
Hi Bob,

ok, now I see your point. I wonder what others think about the suggested alternative syntax for sendAndWait(). Any opinions?
I personally would prefer the sendAndWait() name for the method to sendAndReact(), as having "react" in the name might indicate that the calling thread may get reused by the actor pool and also that the code should be structured in the Continuation Style, just like for real "react" calls. None of this would be the case for our sendAndWait/React() method.

Cheers,

Vaclav


On Sun, Feb 28, 2010 at 12:21 PM, Bob Brown <[hidden email]> wrote:
> thanks for sharing your code. You're doing interesting experiments.

Note sure if it's interesting, but *I'm* learning.

> Please, see the inlined comments:
>
>
>
>
>       Q:
>       I have tried to use sendAndWait with a timeout:
>
>       reply intermediaries[index + 1].sendAndWait(10.seconds,
> "${msg}[$index]")
>
>       This just gives an exception:
>
>       groovy.lang.MissingPropertyException: No such property: seconds
> for class:
>       java.lang.Integer
>
>       I'm missing an import? Couldn't figure out what...
>
>
>
> You need to wrap the code in "use(TimeCategory)" to enable TimeCategory
> DSL, otherwise there's always the option to use the "sendAndWait(final T
> message, final long timeout, final TimeUnit units)" method.

OK. I wasn't sure whether GPars was supposed to be doing this on my
behalf...the doco wasn't quite clear enough on this (IMHO, sorry).

>
>
>       Obs:
>
>       Instead of code like:
>
>       def resp =  theActor.sendAndWait(msg)
>       println "Got $resp"
>       reply resp
>
>       I think I'd like to be able to do something like:
>
>       theActor.sendAndWait(msg) { resp ->
>        println "Got $resp from ${resp.sender}"
>        reply resp
>       }
>
>       Would this be a worthwhile enhancement?
>
>
>
> I guess the sendAndContinue() method is what you're looking for here.
> Although, the reply() method would have to be invoked slightly
differently,
> since plain "reply resp" would reply to the "resp" message, not the
original
> "msg" message.
>
> def sender = msg.sender
> theActor.sendAndContinue(msg) {resp ->
>     println ...
>     sender << resp
> }

Not really, in this case. Since sendAndContinue is non-blocking. It "allows
the caller to continue its processing while the supplied closure is waiting
for a reply from the actor." I was trying to suggest a (to me) more natural
syntax for the blocking (w.r.t. the caller) behaviour.

Actually, I wonder if 'sendAndReact' might be better naming (it isn't just
waiting, but also processing as react would):

theActor.sendAndReact(msg) { resp ->
 println "Got $resp from ${resp.sender}"
 reply resp
}

BOB


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email





--
E-mail: [hidden email]
Blog: http://www.jroller.com/vaclav
Linkedin page: http://www.linkedin.com/in/vaclavpech