Hello guys, Few days ago I've got a case where coalescing actors could be very helpful, but unfortunately couldn't use it in a current coalescing implementation.
Just to illustrate - suppose we have counter actor (exactly like in Actor examples), which accepts Set(val), Get and Incr(val) messages. Basically in this case we can have this actor coalescing (where message key is just a message type) in order to remove unnecessary Sets and collapse Incrs, but we can coalesce Incr msgs only if there is no Set msg between them.
I understand that such cases can be solved by more "specific" key functions sometimes, but I think it would be great if coalesce func could have additional argument Obj?[] keys which contains keys of all messages between messages we trying to coalesce.
What do you think?
brianThu 15 Oct 2009
I can definitely understand and appreciate the use case.
But I'm having a hard time imagining how we could implement that efficiently. It would require exposing the list of pending messages in a thread safe manner.
ivanThu 15 Oct 2009
I might be wrong, but after looking at Java code of Actor and CoalescingQueue it seems that it is possible to use LinkedHashMap instead of HashMap for pending field. Therefore, in CoalescingQueue.coalesce we can create a list containing all keys after calculated key and pass it in coalesce func. So we expose just keys, not messages, and there can be a constraint that keys are either serializable or const, so modifying keys list from user's coalesce function does not break anything. If user wants to get real messages instead of keys, he can just pass "identity" key function, which returns msg as key. Again, since msgs are either const or serializable, this should be safe. I'll try to make a patch this weekend and check if there are any pitfalls
andreyThu 15 Oct 2009
A slight offtopic: probably clojure-alike immutable collections would be helpful here as well as with other usecases where we need to manage data in thread-safe manner?
brianThu 15 Oct 2009
Trying to pass a list to the coalescing function would be pretty expensive compared to what we do today. Maybe we tackle it a little simpler and just say there is a flag that only allows you to coalesce with the last message?
A slight offtopic: probably clojure-alike immutable collections would be helpful here as well as with other usecases where we need to manage data in thread-safe manner?
I would love to have Fan versions of clojure's immutable list and maps.
ivanThu 15 Oct 2009
Got it, agree, flag would be very simple and efficient solution. However I believe there are cases when benefits from coalescing bigger than list passing costs. Probably in a distant prospect it would be great to allow users explicitly specify message queue for actor? Not necessary to give an ability to write completely custom implementations, but ability to select from several queues (ordinary queue, few types of coalescing queues, priority queue).
brianThu 15 Oct 2009
I agree - the real problem is that we don't allow you to have a pluggable queue implementation. That was what we were talking about originally when I added coalescing, but I couldn't figure out how to expose that simply in a thread safe way.
KevinKelleyThu 15 Oct 2009
In CSP there's the notions of Channels, and Processes, and the alphabet of const data types which they pass around.
Fan's Actor probably maps fairly well to a Process, but we've got no notion of the various kinds of Channels. Or, our actor-messages are sort of like the simplest kind of blocking channel.
I'm thinking though that Channels could be implemented as actors. Then, the actor-channel could queue messages in its local storage, or multicast to many listeners; instead of trying to coalesce a queue you'd use an actor-channel that accumulated its received messages until its conditions are met, then forward as appropriate.
Then Fan's actor-messages are just the sequencing mechanism, representing a connection point between a process and a channel.
Not sure how well that'd really work, though.
brianThu 15 Oct 2009
I think the big missing piece right now is that an Actor can't return a response on behalf of another Actor.
ivan Thu 15 Oct 2009
Hello guys, Few days ago I've got a case where coalescing actors could be very helpful, but unfortunately couldn't use it in a current coalescing implementation.
Just to illustrate - suppose we have counter actor (exactly like in Actor examples), which accepts Set(val), Get and Incr(val) messages. Basically in this case we can have this actor coalescing (where message key is just a message type) in order to remove unnecessary Sets and collapse Incrs, but we can coalesce Incr msgs only if there is no Set msg between them.
I understand that such cases can be solved by more "specific" key functions sometimes, but I think it would be great if coalesce func could have additional argument
Obj?[] keys
which contains keys of all messages between messages we trying to coalesce.What do you think?
brian Thu 15 Oct 2009
I can definitely understand and appreciate the use case.
But I'm having a hard time imagining how we could implement that efficiently. It would require exposing the list of pending messages in a thread safe manner.
ivan Thu 15 Oct 2009
I might be wrong, but after looking at Java code of Actor and CoalescingQueue it seems that it is possible to use LinkedHashMap instead of HashMap for
pending
field. Therefore, in CoalescingQueue.coalesce we can create a list containing all keys after calculated key and pass it in coalesce func. So we expose just keys, not messages, and there can be a constraint that keys are either serializable or const, so modifying keys list from user's coalesce function does not break anything. If user wants to get real messages instead of keys, he can just pass "identity" key function, which returns msg as key. Again, since msgs are either const or serializable, this should be safe. I'll try to make a patch this weekend and check if there are any pitfallsandrey Thu 15 Oct 2009
A slight offtopic: probably clojure-alike immutable collections would be helpful here as well as with other usecases where we need to manage data in thread-safe manner?
brian Thu 15 Oct 2009
Trying to pass a list to the coalescing function would be pretty expensive compared to what we do today. Maybe we tackle it a little simpler and just say there is a flag that only allows you to coalesce with the last message?
I would love to have Fan versions of clojure's immutable list and maps.
ivan Thu 15 Oct 2009
Got it, agree, flag would be very simple and efficient solution. However I believe there are cases when benefits from coalescing bigger than list passing costs. Probably in a distant prospect it would be great to allow users explicitly specify message queue for actor? Not necessary to give an ability to write completely custom implementations, but ability to select from several queues (ordinary queue, few types of coalescing queues, priority queue).
brian Thu 15 Oct 2009
I agree - the real problem is that we don't allow you to have a pluggable queue implementation. That was what we were talking about originally when I added coalescing, but I couldn't figure out how to expose that simply in a thread safe way.
KevinKelley Thu 15 Oct 2009
In CSP there's the notions of Channels, and Processes, and the alphabet of const data types which they pass around.
Fan's Actor probably maps fairly well to a Process, but we've got no notion of the various kinds of Channels. Or, our actor-messages are sort of like the simplest kind of blocking channel.
I'm thinking though that Channels could be implemented as actors. Then, the actor-channel could queue messages in its local storage, or multicast to many listeners; instead of trying to coalesce a queue you'd use an actor-channel that accumulated its received messages until its conditions are met, then forward as appropriate.
Then Fan's actor-messages are just the sequencing mechanism, representing a connection point between a process and a channel.
Not sure how well that'd really work, though.
brian Thu 15 Oct 2009
I think the big missing piece right now is that an Actor can't return a response on behalf of another Actor.