Scala's cost of creating immutable objects

I see posts similar to the concept in [1], and it really makes me wonder what the overall implication of using an immutable Map versus a Mutable is. It seems like the Scala developers are very comfortable with letting mutations of immutable data structures take on the cost of the new object, or maybe I was just missing something. If every mutation operation on an immutable data structure returns a new instance, although I understand this is good for thread safety, what if I know how to fine tune my volatile objects to make those same guarantees?

[1] In Scala, how can I do the SQL equivalent of SUM and GROUP BY?

+3


source to share


3 answers


In general, the only way to answer performance questions like these is to profile them in your real code. Microbenchmarks are often misleading (see this benchmark for example ) - and especially if you are talking about concurrency, the best strategy can be very different depending on how concurrent use is in practice.

In theory, a sufficiently intelligent compiler β„’ should be able - perhaps with a linear system (implied or otherwise) - to reproduce all the efficiency benefits of a mutable data structure. In fact, since it has more information about the intent of the programmer and is less constrained by the random details that the programmer had to specify, such a compiler should be able to generate higher performance code - and, for example, GCC rewrites the code into an immutable form (SSA) for optimization purposes. For an example that comes close to home, many real world Java programs have enough bandwidth but have latency issues caused by the Java garbage collector that stops the world to shrink the heap. A JVM that knew that some objects are immutable,will be able to move them around without stopping the world (you can just copy the object, update all references to it and then delete the old copy, since it doesn't matter if some threads see the old version and some of them see the new one).



In practice it depends, and again the only way is to test your specific case. In my experience, for the level of investment of programmer time available for most practical business problems, spending x hours on a (immutable) version of Scala tends to produce a more efficient program than spending the same time on a mutable Scala or Java version - really , in the amount of programmer time it takes to create a reasonably executable version of Scala, it would probably not be possible to fully complete the Java version (especially if we wanted the same defect speed). On the other hand, if you have unlimited time for an experienced programmer and need the best possible performance, you probablywant to use a very low-level mutable language (which is why LAPACK is still written in Fortran) - or even implement your algorithm directly in FPGA, as JP Morgan recently did.

Even so, you probably want to prototype in a higher-level language so you can write tests and compare them to make sure the high-performance implementation is working correctly. In particular, if we're just talking about mutable and immutable in Scala, premature optimization is the root of all evil. Write your program and then if the performance is inadequate, review it and look for hotspots. If you do spend too much time copying an immutable data structure, it is a good time to replace it with a modified version, and check your thread safety guarantees carefully by hand. If you write decoupled code correctly, then it should be easy for you to replace performance-critical elements as and when you need them.and until then, you should be able to reap code development time that is easier and easier to reason about (especially in concurrency cases). In my experience, performance problems in well-written code are much less common than people expect; most software performance problems are caused by poor choice of algorithm or data structure rather than such little overhead.

+7


source


Your question starts with a wrong assumption based on a misunderstanding of the cost associated with using immutable objects.

Working with guaranteed immutable objects that form immutable shape objects allows for structural exchange , so you can create new objects from old ones without resorting to using a deep copy of the object, and you can, roughly speaking, reuse parts of the object on which a new one is founded. Thus, it greatly reduces the impact of using immutable objects.



So what's the difference with finely tuned, hand-crafted mutable objects?

  • immutable objects are better suited to the FP paradigm
  • optimization and compile time checking
  • reduces the likelihood of running exceptions
+1


source


The question is very general, so it is difficult to give a definite answer. It seems that you are just uncomfortable with object allocation in idiomatic scala code used for comprehension and the like.

The scala compiler does not use special magic for fuse operations or object elimination. It is up to the person who writes the data structure to make sure functional data structures use as much as possible from previous versions (structured exchange). Many of the data structures used in scala collections do this quite well. See for example this talk about Functional Data Structures in Scala to give you an overview.

If you are interested in details, book to get Purely Functional Data Structures from Chris Okasaki. The material in this book also applies to other functional languages ​​such as Haskell and OCaml and Clojure.

The JVM is extremely good at distributing and collecting short-lived objects. So many things that seem outrageously ineffective to someone accustomed to low-level programming are actually surprisingly effective. But there are certain situations where mutable state has performance or other benefits. This is why scala does not prohibit mutable state, but only prefers immutability. If you find that you really need to change state for performance reasons, it is generally a good idea to wrap your mutable state with an akka actor instead of trying to get the downstream synchronized properly.

+1


source







All Articles