Coroutines Android Slow Launch Times
See original GitHub issueEvery Android developer knows that the time spent in Application.onCreate()
is very critical.
Therefore, I tried to speedup my app startup by offloading some initialisation work to a coroutine.
However, my profiling results were surprising.
First Try: Dispatchers.IO
val start = System.currentTimeMillis()
GlobalScope.launch(Dispatchers.IO) {
doWork()
}
val time = System.currentTimeMillis() - start
Timber.d("Launch time: $time")
I consistently saw times between 20-30 milliseconds.
Second Try: Dispatchers.Default
Same as the code above, but with Dispatchers.Default
instead of Dispatchers.IO
.
This also took more than 20 milliseconds.
Third Try: Multiple Coroutine Launches
For the sake of profiling, I measured the launch time of multiple coroutines:
val start = System.currentTimeMillis()
for (counter in 1..5) {
GlobalScope.launch(Dispatchers.IO) {
Timber.d("Hello world from coroutine %s", counter)
}
}
val time = System.currentTimeMillis() - start
Timber.d("Launch time: $time")
The average launch time is a little bit better, but it is still not so good. It took more than 50 milliseconds to launch those five coroutines.
Fallback to AsyncTask
I ended up using a classical thread instead of a coroutine. The thread is abstracted by android.os.AsyncTask
:
class PrimitiveAsyncTask(val runnable: () -> Unit) : AsyncTask<Void, Void, Void>() {
override fun doInBackground(vararg params: Void?): Void? {
runnable()
return null
}
}
fun doAsync(runnable: () -> Unit) {
PrimitiveAsyncTask(runnable).execute()
}
doAsync {
doWork()
}
As you would expect, this piece of code took less than 1 millisecond to launch the AsyncTask.
My Setup
I use the following libraries:
org.jetbrains.kotlinx:kotlinx-coroutines-core
org.jetbrains.kotlinx:kotlinx-coroutines-android
As outlined below, I tested this with the versions 1.3.3
and 1.1.1
.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:6
- Comments:14 (5 by maintainers)
I was able to implement a very simple workaround: Launch a dummy coroutine via an AsyncTask from
Application.onCreate()
, in order to initialize the coroutines library ahead of time.For me, this workaround is sufficient for the time being. Nevertheless, it might be advisable to further optimize the initialization code of the coroutines library.
I have now changed the setup of my experiments: Instead of measuring time in the
Application.onCreate()
of my Android app, I have written instrumented Unit tests. Although those Unit tests are still running on an Android device, the Unit tests do not launch any activity or service. As a result, the Unit tests have less noise and I expect a better reproducibility.The results are not as bad as before, but still unsatisfying. Here are the launch times:
Compare this with traditional threads:
EDIT: I produced these results with the tests in this hello world application: https://github.com/fkirc/coroutines-performance-tests