I have a large Mutable Map object which occupies so much memory which all the children of the parent need to access or modify values to the same Map.
I am considering just passing the mutable map during child creation as constructor parameters to all the children upon which they can access or modify the map accordingly.
I just wanted to confirm that SCALA actually passes the object reference around and so the Mutable Map will not be copied all over again, instead all the children will be modifying the same Map instance?
This is a bad idea. The Akka team does not recommend shared mutable state of any kind.
The Akka way to solve your problem would be to make your map immutable and pass it to your children in immutable messages. If you are convinced that the map has to be mutable then have one actor manage the map and have the other actors send messages to it to retrive / update values. There is nothing wrong with mutable state within one actor.
I have a large Mutable Map object which occupies so much memory which
all the children of the parent need to access or modify values to the
same Map
This is exactly what Akka shines at compared to other concurrency mechanisms. Encapsulating mutable state inside an Actor and sending messages to the Actor to mutate the state is the correct and recommended approach.
So you need to pass an ActorRef to any actor who needs to modify the map. The cool thing is that other actor can be on a different JVM and it would still work.
This also takes care of your concern the large memory footprint of your Map.
Related
I notice in many akka examples, in order to show how you can use mutable type inside of an Actor they use:
var users: Map[String, String] = ...
Why don't people use:
val users = scala.collection.mutable.Map[String, String]()
You can still mutate the Map but just cant' change the reference.
Is there a significant difference between the 2 approaches?
In the general case there are issues about visibility of this data, as discussed in the comments. But these don't apply in the case of an Actor because the only way to access data is through messages to the Actor. The actor state is not directly visible to code outside the Actor, so there are no concerns about sharing mutable data.
The main difference between using var and using mutable is that with var the whole collection is replaced but with mutable the collection is updated in place. Updating a collection in place is not functional, so the mutable version tends to encourage non-functional code whereas the var version encourages a more functional programming style.
But Actor state should really be held in the Behavior (for typed Actors) or managed via context.become in classic Actors. In both these cases the state consists of immutable values so, again, the var model is closer to this than using mutable collections.
Here's the scenario. I am creating a simple session handler in Scala and I need a class that can store lists. The class needs other functions associated with it to function properly.
I will be accessing sessions by a session ID
I will rarely be traversing the list
I will be constantly adding and removing from the list
My questions:
What is the proper Scala object to use for this situation?
What is the best way to add or remove an entity from said Scala object?
I am fairly new to Scala so please forgive the elementary question I might be asking. Any assistance would be most appreciated.
Edit: To add to it all...Thread Safty is a factor. The object used must be thread safe or it must be easy to allow for thread safty when adding and removing items by Session ID.
You can use java.util.concurrent.ConcurrentHashMap - it has best performance with guarantied thread safety.
You can use the immutable implementation of HashSet which operations of adding and removing take effectively constant time.
Once this collection is immutable, you'll need to learn the "scala way" of working with collections, how to deal with state and so on. Maybe you'll need to change the way you're working the collections, but this way you won't need to worry about concurrency.
val list = new List(1,2,3,4,5,6,7,8,9,10)
I'm writing a soft in which various actors concurrently create portions of a same graph.
Nodes of the graph are modeled through a class hierarchy, each concrete class of the hierarchy has a companion object.
abstract class Node
class Node1(k1:Node, k2:Node) extends Node
object Node1 {
def apply(k1:Node, k2:Node) = ...
}
class Node2(k1:Node, k2:Node) extends Node
object Node2 {
def apply(k1:Node, k2:Node) = ...
}
...
So far so good.
We perfom structural hashing on the nodes on creation.
That is, each companion object has a HashTable which stores node instances keyed under their constructor arguments, this is used to detect that an instance of a given node class with the same subnodes already exists and to return that one instead of creating a new instance. This allows to avoid memory blowup, and allows have a node equality test that takes constant time (reference comparison instead of graph comparison). Access to this map is protected using a scala.concurrent.Lock.
Yet the problem is that the Lock operate at jvm thread level, and that depending on how actors are coded, they can either be allocated on their own jvm threads, or instead be interleaved with several other actors in a same JVM thread in which case the structural hashing ceases to work (i.e., several structurally identical nodes can be created, and only one of them will be stored in the cache, and the structural equality will cease to work).
First, I know that this structural hashing architecture goes against the actor share-nothing philosophy, but we really need this hashing to work for performance reasons (constant time equality brings us an order of magnitude improvement), but is there a way to implement mutual exclusion on shared ressources with actors that would work at actor level rather than jvm thread level?
I thought of encapsulating the node companion in an actor to completely sequentialize access to the factory but this would imply a complete rewrite of all the existing code, any other idea?
Thanks,
If you have shared mutable state, have a single actor which mutates this state. You can have other actors read, but have one actor that does the writes.
Calling expert Scala developers! Let's say you have a large object representing a writable data store. Are you comfortable with this common Java-like approach:
val complexModel = new ComplexModel()
complexModel.modify()
complexModel.access(...)
Or do you prefer:
val newComplexModel = complexModel.withADifference
newComplexModel.access(...)
If you prefer that, and you have a client accessing the model, how is the client going
to know to point to newComplexModel rather than complexModel? From the user's perspective
you have a mutable data store. How do you reconcile that perspective with Scala's emphasis
on immutability?
How about this:
var complexModel = new ComplexModel()
complexModel = complexModel.withADifference
complexModel.access(...)
This seems a bit like the first approach, except that it seems the code inside withADifference is going to have to do more work than the code inside modify(), because it has to create a whole new complex data object rather than modifying the existing one. (Do you run into this problem of having to do more work in trying to preserve
immutability?) Also, you now have a var with a large scope.
How would you decide on the best strategy? Are there exceptions to the strategy you would choose?
I think the functional way is to actually have Stream containing all your different versions of your datastructure and the consumer just trying to pull the next element from that stream.
But I think in Scala it is an absolutely valid approach to a mutable reference in one central place and change that, while your whole datastructure stays immutable.
When the datastructure becomes more complex you might be interested in this question: Cleaner way to update nested structures which asks (and gets answered) how to actually create new change versions of an immutable data structure that is not trivial.
By such name of method as modify only it's easy to identify your ComplexModel as a mutator object, which means that it changes some state. That only implies that this kind of object has nothing to do with functional programming and trying to make it immutable just because someone with questionable knowledge told you that everything in Scala should be immutable will simply be a mistake.
Now you could modify your api so that this ComplexModel operated on immutable data, and I btw think you should, but you definitely must not try to convert this ComplexModel into immutable itself.
The canonical answer to your question is using Zipper, one SO question about it.
The only implementation for Scala I know of is in ScalaZ.
Immutability is merely a useful tool, not dogma. Situations will arise where the cost and inconvenience of immutability outweigh its usefulness.
The size of a ComplexModel may make it so that creating a modified copy is sufficiently expensive in terms of memory and/or CPU that a mutable model is more practical.
GWT-RPC requires that transfer objects to be serialized must have a default (zero-argument) constructor. Similarly, final fields will not be serialized (see issue 1054).
On the other hand, I know I am supposed to "minimize mutability". My tendency is to want my TOs to be immutable, with final fields, no default constructor, and no mutators.
How can I use GWT-RPC while respecting the immutable paradigm as much as possible. Do I have to convert to a mutable object to marshall, and then back to an immutable one? Is this even worthwhile?
Item 13 in Effective Java (item 15 in second edition) gives strategies on how to minimize mutability or to favor immutability.
Suppose we remove mutators but retain non-final fields and a default constructor. The effect will be a theoretically mutable object, but a practically immutable one. Yes, one could mutate the object via reflection with a bit of effort, but by simply closing off the exposed methods we can at least discourage mutating it in cases like this where it's impractical to make the object truly immutable.