Quantcast

Channels and Actors

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Channels and Actors

cjkent
Hi

I've just started using channels with actors and it appears that a channel has to be created while the body of its actor is running or there's no way to connect it to the actor. Is that right or am I missing something? Currently I can't see a way of creating a class that extends Actor and exposes Channels as fields (except using vars but that feels like a hack and is prone to race conditions unless you're careful).

All the example code I've seen that uses channels shows the channels passed out of the actor by sending them as messages to other actors. Is this supposed to be the only way that channels can be used and if so why? Channel already has a constructor that takes an actor to use as its receiver but it's not public. Would it be possible to make it public or is there a reason why that wouldn't be a good idea?

Thanks
Chris
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [scala] Channels and Actors

Philipp Haller-2
Hi,

cjkent wrote:

> I've just started using channels with actors and it appears that a channel
> has to be created while the body of its actor is running or there's no way
> to connect it to the actor. Is that right or am I missing something?
> Currently I can't see a way of creating a class that extends Actor and
> exposes Channels as fields (except using vars but that feels like a hack and
> is prone to race conditions unless you're careful).
>
> All the example code I've seen that uses channels shows the channels passed
> out of the actor by sending them as messages to other actors. Is this
> supposed to be the only way that channels can be used and if so why? Channel
> already has a constructor that takes an actor to use as its receiver but
> it's not public. Would it be possible to make it public or is there a reason
> why that wouldn't be a good idea?

You are right that exchanging channel references is a bit clumsy that
way. And it also does not add much to safety, either. So, I think it is
a good idea to make the unary constructor of the Channel class public.

Philipp

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[scala] actor receive

Judson, Ross
I got bitten a few days ago by actor receive...the short version is that
I set up an actor, called into the Scala interpreter from within that
actor supplying a local function (in the actor) as a callback. When the
interpreter needs a line of input, it called my callback, where I have
the actor's receive. The receive grabs a line of input from its message
queue, then returns that to the interpreter. Overkill? Sure, but
sometimes you just want to play with the neat actor facility.

Except that it didn't work, and it was driving me nuts...I finally
tracked it down...the first thing the Scala interpreter does on the
_first_ line of input is use a _future_ to do the calculation...that
resulted in the first invocation of my callback occurring on a thread
that did not have the actor machinery set up, and led to no behavior.

It's my understanding that an actor receive executed when the actor
setup has not been performed will simply never return, and cannot be
"unlocked". If that's the case, I believe that it would be appropriate
to signal an error...or find a way to permit this to work correctly.
When we're dealing with actors we don't want to have to think much about
threads, and the requirement that the thread have actor setup performed
somewhere up the stack is a bit painful -- particularly when the
underlying library may engaged in thread-shifting behaviors of its own!

Which brings up the sticky mess of lexical scoping vs. threading...what
the actor library does, in effect, is say that in a given scope you
might be executing in ay thread...

RJ
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [scala] actor receive

David Pollak
In lift, I go through great pains to make sure that Comet Actors get
messages that contain the functions that they need to execute (the
callbacks that were linked to form elements, ajax elements, etc.) so the
execution is always done in the scope of the Actor (within a receive/react.)

There's nothing like a hybrid model to make one think about things like
this!

Judson, Ross wrote:

> I got bitten a few days ago by actor receive...the short version is that
> I set up an actor, called into the Scala interpreter from within that
> actor supplying a local function (in the actor) as a callback. When the
> interpreter needs a line of input, it called my callback, where I have
> the actor's receive. The receive grabs a line of input from its message
> queue, then returns that to the interpreter. Overkill? Sure, but
> sometimes you just want to play with the neat actor facility.
>
> Except that it didn't work, and it was driving me nuts...I finally
> tracked it down...the first thing the Scala interpreter does on the
> _first_ line of input is use a _future_ to do the calculation...that
> resulted in the first invocation of my callback occurring on a thread
> that did not have the actor machinery set up, and led to no behavior.
>
> It's my understanding that an actor receive executed when the actor
> setup has not been performed will simply never return, and cannot be
> "unlocked". If that's the case, I believe that it would be appropriate
> to signal an error...or find a way to permit this to work correctly.
> When we're dealing with actors we don't want to have to think much about
> threads, and the requirement that the thread have actor setup performed
> somewhere up the stack is a bit painful -- particularly when the
> underlying library may engaged in thread-shifting behaviors of its own!
>
> Which brings up the sticky mess of lexical scoping vs. threading...what
> the actor library does, in effect, is say that in a given scope you
> might be executing in ay thread...
>
> RJ
>  

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[scala] Re: actor receive

Lex Spoon-3
In reply to this post by Judson, Ross
"Judson, Ross" <[hidden email]> writes:
> Except that it didn't work, and it was driving me nuts...I finally
> tracked it down...the first thing the Scala interpreter does on the
> _first_ line of input is use a _future_ to do the calculation...that
> resulted in the first invocation of my callback occurring on a thread
> that did not have the actor machinery set up, and led to no behavior.

Ah yes.  :) You should set up the interpreter with -Xnojline.  Then it
will not do anything fancy like that.


-Lex

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [scala] actor receive

Philipp Haller-2
In reply to this post by Judson, Ross
Ross,

Judson, Ross wrote:
> Except that it didn't work, and it was driving me nuts...I finally
> tracked it down...the first thing the Scala interpreter does on the
> _first_ line of input is use a _future_ to do the calculation...that
> resulted in the first invocation of my callback occurring on a thread
> that did not have the actor machinery set up, and led to no behavior.
>
> It's my understanding that an actor receive executed when the actor
> setup has not been performed will simply never return, and cannot be
> "unlocked".

It is actually possible to use send/receive from a thread that is not
set up as an actor. Here is an (executable) example:

import scala.actors.Actor
import scala.actors.Actor._

object threads extends Application {
  val a = actor {
    receive {
      case other: Actor =>
        other ! 'hello
        receive {
          case any => println("response: "+any)
        }
    }
  }
  val t = new Thread(new Runnable {
    def run() {
      a ! self
      receive {
        case 'hello =>
          println("got 'hello")
          sender ! 'world
      }
    }
  })
  t.start()
}

In this example, `t' is able to send its (lazily created) actor
identity, `self', to actor `a'. After that it can receive messages as if
it was a normal actor. What you cannot do is sending a message directly
to the thread as in `t ! msg'. Currently, there is no implicit
conversion defined that would turn a `Thread' into a `RichThread' with
this method. You cannot obtain a thread's actor identity "from outside"
either, as in `t.self'. So, currently a thread itself needs to invoke
`self', and pass it on to other actors, before it can engage in actor
communication.

> If that's the case, I believe that it would be appropriate
> to signal an error...or find a way to permit this to work correctly.

So, one could indeed signal an error when a non-actor thread calls
`receive' without having called `self' before, since there is no way
other actors could find out its actor identity, and therefore there is
no way it could receive messages.

Alternatively, one could provide a way to obtain a thread's actor
identity "from outside" which could even be done using an implicit
conversion I believe.

> Which brings up the sticky mess of lexical scoping vs. threading...what
> the actor library does, in effect, is say that in a given scope you
> might be executing in ay thread...

I am not sure what you mean exactly, but I'd like to point out that
(even if this is no news for you I mention it anyway since it might be
interesting for other readers and provide a basis for further
discussion) one important motivation for actors is that they allow you
to avoid control inversion meaning that there is at most one thread
executing inside an actor at a time, and the user chooses when this is
going to happen by writing a straight-line program that waits for
messages at explicit points in the control flow.

In this model, one usually wants to avoid passing callback functions out
to other threads that invoke them asynchronously; instead, other threads
should interact with an actor only by sending messages to it. If
callback-like behavior is wanted then the following pattern achieves it
in a thread-safe manner:

  def eventloop() {
    react {
      case Event1 =>
        // handle Event1
        eventloop()
      ...
      case Eventn =>
        // handle Eventn
        eventloop()
    } }

This pattern is provided as an abstract operation in `Actor.eventloop':

  import scala.actors.Actor._

  eventloop {
    case Event1 =>
      // handle Event1
    case Eventn =>
      // handle Eventn
  }

Note that there is no need for tail calls to some enclosing function any
more.

Coming back to the threads interaction business, I think it would be
helpful to look at concrete example code, so that we can discuss
concrete solutions.

Cheers,
   Philipp

Loading...