Blog Post

#500 Build 1.0.40 (Actors)

brian Thu 2 Apr 2009

I have posted the latest build and updated the online docs.

The primary new feature of this build is the new Actor Framework. I am pretty excited how it turned out.

Note: the .NET implementation is still not quite complete yet.

For this one build, I have maintained the old Thread API side-by-side with the new Actor API. Hopefully this will help ease transition issues if you have code to refactor. I refactored all of our Bespin code which was heavily concurrent, and it went pretty smoothly. Let me know if you have any issues.

Starting tomorrow I will remove the old Thread API from the Mercurial tip. Then immediately begin on it-blocks.

Change Log

Build 1.0.40 (2 Apr 09)

  • Added sys::Actor API
  • Added sys::Service API
  • Renamed UnknownThreadErr to UnknownServiceErr
  • Refactor fand to work with Services
  • SqlService API changed from Thread to Service
  • Image resize
  • ScrollBar added
  • ProgressBar.value renamed val

cbeust Fri 3 Apr 2009

This is looking great, Brian!

Quick remark: the first example says "with receive function", but don't you mean this comment for the second piece of code?

-- Cedric

brian Fri 3 Apr 2009

The old Thread API has been removed from Mercurial tip.

I also re-organized the source tree a bit:

  • src/jfan => src/sys/java
  • src/nfan => src/sys/dotnet

This keeps the sys pod consistent with how the other pods with native code are structured (good idea from qualidafial). Note that the java/C# build scripts still work like they used.

brian Fri 3 Apr 2009

Quick remark: the first example says "with receive function", but don't you mean this comment for the second piece of code?

Hi Cedric - glad to see you pop in!

My comment was probably a little confusing, I reworded to be a little more clear:

// pass receive to constructor as a closure function
a := Actor(group) |Int msg->Int| { msg + 1 }

// subclass and override receive
const class IncrActor : Actor
{
  new make(ActorGroup g) : super(g) {}
  override Obj? receive(Obj? msg, Context cx) { msg->increment }
}

cbeust Fri 3 Apr 2009

A few additional remarks:

everytime it receives a message:

"every time"

echo("Count is now " + a.send("ignored").get)

Don't you mean "count" instead of "ignored"?

If a timeout used

"is used"?

Often when sending messages to a actor

"an actor"

The coalescing example confuses me somewhat. I'll have to read it again more carefully, but I think my confusion comes mostly from the fact that I'm not sure how much of the behavior that you describe is performed by the Actor framework and how much of it is done by the user but not described in the code snippet.

Is coalescing that common or is it just a need you came across in FWT and decided to incorporate in the Actors framework?

peek of 100 threads

"peak"

actor's currently have work.

"actors"

Once all actor's

"actors"

Finally, just a minor style issue: when you write

|Repaint a, Repaint b->Obj|

Because of the spaces, I visually see two portions: "Repaint a" and "Repaint b->Obj", which tripped me a few times when reading the code. I prefer to write

|Repaint a, Repaint b -> Obj|

No need to respond, it's just personal taste :-)

brian Fri 3 Apr 2009

Thanks for catching all the typos Cedric. I've posted fixes to the online docs.

Is coalescing that common or is it just a need you came across in FWT and decided to incorporate in the Actors framework?

I don't actually use it in the FWT, I just picked what I figured was one of the most common examples. But I do use coalescing in probably 50% of all my actors in SkyFoundry's production code - it is one the most important features for building high performance queues. So it is a pretty important feature. Originally we were going to make it pluggable, but since it requires low level knowledge of the queue and futures I put it directly into the framework.

All the user code does is provide a toKey and coalescing function, the framework takes care of the rest.

cbeust Fri 3 Apr 2009

I don't actually use it in the FWT, I just picked what I figured was one of the most common examples. But I do use coalescing in probably 50% of all my actors in SkyFoundry's production code - it is one the most important features for building high performance queues. So it is a pretty important feature. Originally we were going to make it pluggable, but since it requires low level knowledge of the queue and futures I put it directly into the framework.

Alright, I'll take your word for it. I have never written Actor-based software myself, so I don't know.

All the user code does is provide a toKey and coalescing function, the framework takes care of the rest.

Ah, that wasn't immediately clear to me from reading the code. You might want to specify that these two methods need to be provided by the developer in order to use Coalescing.

-- Cedric

qualidafial Fri 3 Apr 2009

I'm wondering whether the toKey function sent to Actor.makeCoalescing should allow returning null as a magic value, given that null is a valid message for Actor.send.

brian Fri 3 Apr 2009

I'm wondering whether the toKey function sent to Actor.makeCoalescing should allow returning null as a magic value, given that null is a valid message for Actor.send.

Null indicates that the message can't be coalesced. So I think it this is OK. The key used for coalescing is orthogonal to the actual messages. So even if null was actually a message you wanted to coalesce you could potentially use some non-null key such as "_null_".

qualidafial Fri 3 Apr 2009

From the fandoc:

If coalesce is null, then we use the incoming message (last one wins).

When I read this I thought this meant if the result of calling coalesce(), not whether coalesce == null. It would help if this were clarified in the fandocs.

Null indicates that the message can't be coalesced.

This is not explained in the fandocs.

brian Fri 3 Apr 2009

When I read this I thought this meant if the result of calling coalesce(), not whether coalesce == null. It would help if this were clarified in the fandocs.

It is meant to be read as "if the coalesce function itself is null". I will update the fandoc.

This is not explained in the fandocs.

This is the specification in the fandoc regarding the toKey function:

The toKey function is used to derive a key for each message, or if null then the  
message itself is used as the key. If the toKey function returns null, then the 
message is not considered for coalescing.

qualidafial Fri 3 Apr 2009

This is the specification in the fandoc regarding the toKey function:

Actually I was speaking about coalesce, not toKey.

qualidafial Fri 3 Apr 2009

I see I said toKey in my original comment when I meant to say coalesce. Sorry for the confusion. Let me start over:

If toKey returns non-null and the coalesce function is non-null, then what happens if coalesce decides that two events that are keyed the same cannot be coalesced? Return null?

brian Sat 4 Apr 2009

If toKey returns non-null and the coalesce function is non-null, then what happens if coalesce decides that two events that are keyed the same cannot be coalesced? Return null?

OK, I was confused then - thought you were talking about the toKey function. Your only hook to opt out of coalescing is the toKey function. If two messages have the same key they are going to be coalesced regardless of what coalesce returns. If the coalesce function returns null, then the messages are coalesced into null (since that is a valid message, one I happen to use all the time actually).

But I can't ever really see it being a problem, because you have the toKey function to make a coalescing decision. Remember you can always coalesce into something, even if it just means keeping track of both messages. For example in one of my actors all coalescing does it create a linked list of the messages (the key is a time range).

brian Fri 24 Apr 2009

I was thinking today that maybe ActorPool would be a better class name than ActorGroup. Just throwing it out there. If there is strong consensus to rename that class, I think it might be a more accurate name.

JohnDG Sat 25 Apr 2009

ActorPool is indeed a better name than ActorGroup, which was itself better than ActorService.

brian Thu 30 Apr 2009

I renamed ActorGroup to ActorPool

Login or Signup to reply.