4

I develop apps for Android. I was wondering how many Kotlin Stateflows can I observe at one time? Every observe that I do is done on different CoroutineScope created by myself, dispatched by IO dispatcher or provided by lifecycle components of Android frameworks.

I have done various operations such as simple additions in infinite loop inside coroutines and using Android Studio profiler I have observed that launching a lot of coroutines that perform calculations causes high load on CPU.

Having in mind that Stateflow never completes, every collect on it is blocking and done on different CoroutineScope as examples and docs says, what is maximum amount of Stateflows that I can observe at one time without bothering that I will highly use CPU, create too many threads or just simply run out of device resources?

  • 2
    Shouldn't the collection typically be done on an existing `lifecycleScope` or `viewModelScope` since you usually only want to collect to something that is dependent on one of those lifetimes? I don't think you should frequently need to create your own CoroutineScope. There certainly are applications for it and they're very lightweight, but if you're doing it for every flow that you collect, that is unnecessary boilerplate, because to properly cancel them, then you need a property to store each one and to manually cancel them all at the appropriate time. – Tenfour04 Aug 18 '21 at 21:03
  • Couldn't agree more with @Tenfour04. If you create new scopes for every collection, you're likely doing something wrong. Do you confirm you actually cancel those scopes at some point? A `CoroutineScope()` call is definitely *not* a drop-in replacement for `GlobalScope` usages. – Joffrey Aug 18 '21 at 21:19
  • 1
    *Stateflow never completes, every collect on it is blocking* - no they are not. Collecting a StateFlow is not blocking a thread, it's a suspending operation like other suspending functions, and it's fine to launch many of those collections concurrently. However, you need to control the scopes you are launching this collections in. In particular, you should make sure you cancel the scope associated with the lifecycle of the component you created it in (to avoid leaks). – Joffrey Aug 18 '21 at 21:23
  • Yes, you all are right - when it comes to android components I use their `lifecycleScopes`. But sometimes I need to use coroutines in pure kotlin classes (lets name that class `Collector`), for example to observe phone components such as Bluetooth or GPS and then send info to server whether they are turned on or off. I collect that info from flows, so inside `Collector` I need to create new `CoroutineScope` and thats main root of question, because I was wondering about observers that are not bound to android components. – CuriousMate Aug 19 '21 at 07:25

1 Answers1

5

Subscriptions are still coroutines, and coroutines are cheap. There's definitely no universal bound we could tell you.

every collect on it is blocking

It suspends, it doesn't block. And you can always use takeWhile or the like to only collect from it until you can stop, or you can cancel the coroutine that's doing the collection (e.g. with withTimeout).

The main constraint on performance is that updating a MutableStateFlow takes time linear in the number of subscribers to that StateFlow, so if you update a StateFlow with a thousand subscribers, it'll take ~a thousand times longer than updating a MutableStateFlow with only a single subscriber.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413