const class SingletonMap
{
const static SingletonMap val := make()
Obj? get(Str name) { actor.send(name).get(200ms) }
Void set(Str name, Obj? val) { actor.send([name, val]) }
private new make()
{
actor = Actor(ActorPool()) |msg| { receive(msg) }
}
private Obj? receive(Obj? msg)
{
Str:Obj? map := Actor.locals.getOrAdd("map") { Str:Obj[:] }
if (msg is Str)
return map[msg]
else
return map.set(msg->get(0), msg->get(1))
}
private const Actor actor
}
Which (once I got my head around it) makes sense. Having done a lot of thread programming, of course, I got to thinking about how it doesn't have any synchronize type calls in it.
So I'm curious if the following thinking is correct.
First, SingletonMap has its own private const Actor which it delegates to. As I understand it, an Actor contains (in effect) its own thread, and so when you send to it, you're asking another thread to do work for you. This is how Actor.locals can be "the same" even though a SingletonMap can be called by multiple threads.
When two threads calls SingletonMap.set (effectively) simultaneously with some key and value pairs, since it's a single thread handling both requests, the requests are serialized so that one runs after the other completes. In effect, there is some kind of barrier synchronization in the private SingletonMapActor object so the two calling threads don't simultaneously try to change the underlying Map object.
Right? Sorry to muddy the waters by bringing up threads in an Actor world, but I'm trying to make the mental leap, and I want to make sure I know what I'm doing... and that it's safe.
vkuzkokovFri 10 Sep 2010
I just looked through Java code (of curiosity). Actor implementation submits itself to thread pool for execution if it's already enqueued or running. Thus, it's guaranteed that Actor is never run on more than one thread.
Here goes a big difference for Fantom, because you can't access "concurrency protected " (Actor.locals) data from outside of "synchronized" block.
brianFri 10 Sep 2010
Just a high level of how actors actually work...
When you send an actor a message you are enqueuing the message onto a message queue. It is the queue which under the covers is handling the "synchronization" for you. All the calling thread must do is to grab a lock long enough to ensure that the message is safely enqueued.
Then there is a scheduling mechanism within ActorPool which schedules actors onto threads for execution. If an actor has pending messages then it is allocated to a thread to process that message (assuming that the pool hasn't hit its max thread pool limit). This turns out to be very efficient use of the threads because just a couple threads can be used to service 1000s of actors, especially if the actors don't have a lot of messaging.
Threads in an actor pool eventually die off after a keep-alive period. So even if you have 1000s of actors, if none of them are actually processing messages there then no threads are used.
vkuzkokovFri 10 Sep 2010
Eventually, I would like to have synchronous send. I believe something like fully separate SyncActor is the easiest way to achieve it.
brianFri 10 Sep 2010
Eventually, I would like to have synchronous send. I believe something like fully separate SyncActor is the easiest way to achieve it.
If you want it to be synchronous, just block on the Future with a call to get:
send(msg).get
That will block the calling thread until the actor has processed the message and returned a result.
Or maybe you are asking for something different?
vkuzkokovFri 10 Sep 2010
Yes. Something that would have only one synchronized block in Java counterpart and no compulsory thread switching.
yachrisFri 10 Sep 2010
Just a high level of how actors actually work...
Thanks, Brian, for the info. Enlightening.
Thanks to vkuzkokov for digging into the Java.
MoOmSun 12 Sep 2010
Eventually, I would like to have synchronous send. I believe something like fully separate SyncActor is the easiest way to achieve it.
I find this proprosal very interesting. The biggest problem I have with Actor is that it requires code to be executed in a separated thread, thus generating a non-negligible overhead. As vkuzkokov said, a SyncActor would only require a lock and would offer better performances for all sync operations. For example, the cache system proposed in #1201 would probably be more efficient it it were using a SyncActor.
What do you think about it brian?
brianMon 13 Sep 2010
What do you think about it brian?
I have concerns about anything that resembles a synchronized block of code. So far my experience is that actors perform really fast because there is never any locking contention.
Although one technique I do also use is AtomicRefs to update a static reference to an immutable data structure. In general I would think this is probably what you are trying to achieve with a "sync actor".
yachris Fri 10 Sep 2010
(There's a great "Fantom of the Opera" pun in here, I'm sure of it :-).
So in the earlier discussion of the
SingletonMap
object, Brian gave the following code:Which (once I got my head around it) makes sense. Having done a lot of thread programming, of course, I got to thinking about how it doesn't have any
synchronize
type calls in it.So I'm curious if the following thinking is correct.
First,
SingletonMap
has its own private const Actor which it delegates to. As I understand it, an Actor contains (in effect) its own thread, and so when yousend
to it, you're asking another thread to do work for you. This is howActor.locals
can be "the same" even though aSingletonMap
can be called by multiple threads.When two threads calls
SingletonMap.set
(effectively) simultaneously with some key and value pairs, since it's a single thread handling both requests, the requests are serialized so that one runs after the other completes. In effect, there is some kind of barrier synchronization in the privateSingletonMap
Actor
object so the two calling threads don't simultaneously try to change the underlyingMap
object.Right? Sorry to muddy the waters by bringing up threads in an Actor world, but I'm trying to make the mental leap, and I want to make sure I know what I'm doing... and that it's safe.
vkuzkokov Fri 10 Sep 2010
I just looked through Java code (of curiosity). Actor implementation submits itself to thread pool for execution if it's already enqueued or running. Thus, it's guaranteed that Actor is never run on more than one thread.
As of mental leap. Consider
and
Here goes a big difference for Fantom, because you can't access "concurrency protected " (Actor.locals) data from outside of "synchronized" block.
brian Fri 10 Sep 2010
Just a high level of how actors actually work...
When you send an actor a message you are enqueuing the message onto a message queue. It is the queue which under the covers is handling the "synchronization" for you. All the calling thread must do is to grab a lock long enough to ensure that the message is safely enqueued.
Then there is a scheduling mechanism within ActorPool which schedules actors onto threads for execution. If an actor has pending messages then it is allocated to a thread to process that message (assuming that the pool hasn't hit its max thread pool limit). This turns out to be very efficient use of the threads because just a couple threads can be used to service 1000s of actors, especially if the actors don't have a lot of messaging.
Threads in an actor pool eventually die off after a keep-alive period. So even if you have 1000s of actors, if none of them are actually processing messages there then no threads are used.
vkuzkokov Fri 10 Sep 2010
Eventually, I would like to have synchronous send. I believe something like fully separate
SyncActor
is the easiest way to achieve it.brian Fri 10 Sep 2010
If you want it to be synchronous, just block on the Future with a call to
get
:That will block the calling thread until the actor has processed the message and returned a result.
Or maybe you are asking for something different?
vkuzkokov Fri 10 Sep 2010
Yes. Something that would have only one
synchronized
block in Java counterpart and no compulsory thread switching.yachris Fri 10 Sep 2010
Thanks, Brian, for the info. Enlightening.
Thanks to vkuzkokov for digging into the Java.
MoOm Sun 12 Sep 2010
I find this proprosal very interesting. The biggest problem I have with
Actor
is that it requires code to be executed in a separated thread, thus generating a non-negligible overhead. As vkuzkokov said, a SyncActor would only require a lock and would offer better performances for all sync operations. For example, the cache system proposed in #1201 would probably be more efficient it it were using aSyncActor
.What do you think about it brian?
brian Mon 13 Sep 2010
I have concerns about anything that resembles a synchronized block of code. So far my experience is that actors perform really fast because there is never any locking contention.
Although one technique I do also use is AtomicRefs to update a static reference to an immutable data structure. In general I would think this is probably what you are trying to achieve with a "sync actor".