Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does using by lazy make my Kotlin code slower

Tags:

kotlin

I have some code that generates large amounts of instances of a small data class. When I added one lazy property to the class I noticed that creating instances of this class became much slower even if the lazy property is never accessed. How come this happens? I was expecting that there would be no difference if the lazy property is never accessed. Is there any way of using lazy properties without taking this kind of performance hit?

Here's a minimal example:

import kotlin.system.measureTimeMillis

class LazyTest(val x: Int) {
    val test: Int by lazy { 9 }
}

fun main(){
    val time = measureTimeMillis { List(500_000) {LazyTest(it) }}
    println("time: $time")
}

When running this on on play.kotlinlang.org it takes 500-600 milliseconds, if I comment out the line val test: Int by lazy { 9 } it instead takes around 40 milliseconds to run.

like image 735
nibarius Avatar asked Oct 18 '25 03:10

nibarius


2 Answers

Using by lazy creates a second object to "hold the laziness," implementing the lazy calculation. This is most likely responsible for the slowdown.

like image 165
Louis Wasserman Avatar answered Oct 21 '25 01:10

Louis Wasserman


lazy delegates default to using synchronization for thread safety:

By default, the evaluation of lazy properties is synchronized: the value is computed only in one thread, and all threads will see the same value. If the synchronization of initialization delegate is not required, so that multiple threads can execute it simultaneously, pass LazyThreadSafetyMode.PUBLICATION as a parameter to the lazy() function. And if you're sure that the initialization will always happen on the same thread as the one where you use the property, you can use LazyThreadSafetyMode.NONE: it doesn't incur any thread-safety guarantees and the related overhead.

Synchronization incurs a bunch of overhead, and if you're doing a lot of it (with lots of lazy properties) you're probably going to see some slowdown. If you know you're only accessing the property on one thread, or if you know what you're doing and can handle the thread safety yourself, you can pass those other parameters to change the synchronization behaviour.

This doesn't actually apply to your example since you're not actually accessing your properties (you're just creating half a million objects holding half a million delegates, that takes some time!) but it's a good thing to be aware of when you use them.

like image 23
cactustictacs Avatar answered Oct 21 '25 00:10

cactustictacs