Tuesday, 12 November 2019

kotlin, weak and threadLocal delegate

A bit of kotlin today.

Kotlin has a nice and very useful feature called delegated properties. This allows software engineers to add special behavior around a property. For example with the lazy delegate you can delay the calculation of the field.  This may be useful if the calculation is expensive and the calculated value can be re-used multiple times.

The standard library comes with a very modest set of delegates, and to be honest other than the lazy, I haven't found them really useful, but I wrote a couple of delegates that I have found good use of, let's begin with...

threadLocal


Java comes with quite a few utility classes, which we in many cases would like to have as a constant and share it between all threads of the code, until we find that ohhh... surprisingly, they are not thread safe. Probably the most common ones are:
  • SimpleDateFormat
    SimpleDateFormat is indeed the fastest way of parsing date and times and formatting string from Date objects, but it is absolutely not thead-safe, therefore you may be making a billion dollar mistake if you share them as static final.
  • All of the traditional XML processing APIs: DOM, XPath, etc...
    Quite annoying, because they are also very expensive to initialize. I wonder what was the design idea... but anyway


The simple solution is: you do not share them, you do not reuse them, each time you need such an object, you produce one your code refers to it just as local variable, you leave it to the garbage collector after processing.

This will be safe, but a bit slow... or kind of slow if you need to do this a lot.

There is a more performant solution: you declare a ThreadLocal.



Now it is safe for multiple threads, but doesn't look pretty does it? No, it looks crap.

Let's see what can kotlin do for us:

Doesn't this look a lot more human-readable? And just as safe as the java counterpart.

weak

Weak is almost like lazy. It is actually lazy, because the expression will be evaluated at first use. The difference is that reference to the stored value will be weak and therefore whenever the JVM is running low on memory the garbage collector is free to throw them away. Once the results of the calculations are dropped, they will be recalculated again when needed, therefore we balance between good performance and memory limits.



I have found this very useful when working with large data-structures. Of course it is a little bit slower when accessing the stored value compared to the lazy delegate, that is the overhead of using and checking the weak reference.

Give it a try, tell me what you think


The delegates are packaged in kroki-delegates package and deployed in maven central and the code is shared on github.

Use it for good, never for evil.














Sunday, 28 April 2019

String.intern() and performance

In this blog I already wrote about the relationship of cache misses and performance in the KVM virtual machine. I have revisited the topic this weekend with another type of VM: the java virtual machine.

Let's have a list of Strings with some duplication, like (Bob, Sue, Joe, Bob, John, etc). Typically when you read the input from a database or from JSON on a REST API, all strings are a separate object, even if they are the same - like 'Bob' in the example.

Now the question is: how does it change the performance of an algorithm if we de-duplicate this list, therefore each string with the same value should actually be the same String object.

Why would it be any different? Because when the algorithm needs to access the data, it is less likely that it will miss the cache built into the CPU and therefore has to wait.

My benchmark does the same algorithm (sort) first on the non-deduplicated data, and then on the de-duplicated data, on this benchmark we can see the rate of the two results. Of course 1 means they are the same. The different colors show how many different string values there were in the list.


So when does it make sense to deduplicate?
  • Will we elliminate any duplicates?
  • What amount of data is there there be?
  • What is the cost of the deduplication? - e.g. Strings have a constant cost with String.intern
  • For how long / how many times can we enjoy not missing the cache? - typically if you just get the data through JSON and insert it into the DB, then you do not save much time. If you keep the data in memory and process it very frequently, then it with each processing we save a little time
  • Also depends on what type of processing you do, in case of sorting you have to access the data quickly many times after each other. In case of e.g. JSON serialization with jackson, you need to access each data only once, and you can expect smaller difference in performance.

Benchmark source code published on github. Feel free to try, but I have to warn you that it takes 28 hours to run this benchmark.