Hello all, I've read all on KN concurrency but sti...
# kotlin-native
a
Hello all, I've read all on KN concurrency but still cannot figure out how to model this: • There is an
DataFetcher
and `DataStorage`classes, for getting data from remote to storing it, well, into the storage object • The list of
DataFetchers
is global, but mutable using `frozenCopyOnWriteList<>`from
Stately
lib => therefore all Fetchers are frozen • To tell a Fetcher which storage he needs to store the date into, I pass the Storage object in constructor. • PROBLEM: since Storage is then in the same object graph as the Fetcher, Storage becomes frozen. But it's counter-goal for a storage object. There should be a pattern for that, isn't it?
k
Some options to consider. It also kind of depends on what the data looks like, and if it changes often. The basic rules with native are as follows: 1) mutable state can only be “seen” by one thread at a time, 2) frozen state can be shared. If the stored data is being retrieved from the storage and passed around to other threads (UI, etc), and especially if it doesn’t change super often, you can keep it in another frozen structure and mutate that with atomics (which is what stately does)
If you’re changing state a lot, this may be a performance issue. See discussion: https://github.com/square/sqldelight/issues/1226
Is the list of fetchers a pool? Is that to increase performance? I would maybe change that structure. Have a pool of data fetching threads, and keep the fetcher and storage local to that thread, then use regular mutable containers.
I’ve been meaning to write a blog post about rethinking architecture for native and this is a pretty good example.
If fetchers are for different types/sources of data, that won’t work though. I mean I guess it could, but it would depend on how many fetchers you have.
Alternatively, assuming the “fetcher” is hitting the network, you could keep all of your storage in a single thread/worker, and read/writes are performed by worker operations, and the storage itself is mutable state local to that worker.
Doing that with a regular hash map took about 1.8 seconds to run 100k. Replacing with a frozen map it takes about 16 seconds to run, although I only ran it once each, and it could probably be implemented better, but still. Stately’s frozen collections can be useful, but there are alternatives.
a
These all is extremely useful for me, thank you. Fetchers actually retrieve data from different REST API instances and store it in storage. Then, UI elements want to be notified on any change for particular value (Observer). There are usually N Fetchers for 1 Storage but not for performance, each fetches different data.
k
Notifying the UI will also be complicated by all of this, as a listener likely retains a reference to the UI, and will attempt to freeze it
a
So I think to myself, if I use workers to fetch&store, I need to transfer mutable values to UI thread, right?
k
In my example, the data itself is frozen, but the store (in that case a map) is mutable
I assume the UI will need to register a listener. To avoid freezing the UI, the listener needs to keep a reference local to the UI’s thread (I’m assuming a “main thread changes the UI” architecture, which pretty much all UIs have)
I’m likely to refactor that with a StableRef. The ThreadLocalRef works, but it’s not my favorite design
a
<me goes studying code examples> .... thank you
k
You’re welcome! The reaktive thing is newly added. Just FYI. The master branch has a similar Pub/Sub architecture in it https://github.com/touchlab/DroidconKotlin/blob/master/sessionize/lib/src/commonMain/kotlin/co/touchlab/sessionize/architecture/MainThreadPubSub.kt#L8