I playing around with Kotlin and Coroutines in my demo android application.
Here's what I have:
fun testCoroutine3() = runBlocking {
var num = 0
val jobs = List(10_000) { // create a lot of coroutines and list their jobs.
launch(CommonPool) {
delay(1000L)
println(num++)
}
}
for(job in jobs) {
job.join() //wait for all jobs to finish
}
println("FINAL RESULT $num")
}
Basically I'm creating a list of 10,000 Coroutines that wait for 1 second and print a number then increment it.
Then when all jobs are done I print the final result.
(This demo is taken from the GitHub Documentation)
Now most of my test run fine, all the coroutines run almost simultaneously, and my final result is 10000
However in some rare occasions, I am getting the final result as 9,999
This become more obvious when I increase the number to 50,000 for example:
Is it possible that Kotlin is skipping some coroutines when there's a lot of them? on the 50,000, looks like it skipped 2
Or is something else happening here?
num++ consists of two operations: tmp = num + 1 and num = tmp. When dealing with multithreading like your example there are cases where some operations might overwrite the results of another thread, leading to cases like your example.
If you want to know more, research "race conditions" where the end result depends on a "race" between two seperate processes.
Related
I am developing an android app. I'm having a hard time writing code that adds a to-do list to a calendar. Let me show you the code first.
private fun addTodoList(entity: MyTodo) {
val start = Calendar.getInstance()
val end = start.clone() as Calendar
end.time = SimpleDateFormat("MM dd, yyyy", Locale.getDefault()).parse(Date.END_OF_DAY)!!
CoroutineScope(Dispatchers.Default).launch {
val id = MyDatabase.getInstance(mContext).getTodoDao().insert(entity)
val dao = MyDatabase.getInstance(mContext).getCalendarDao()
do {
val date = ymd.format(start.timeInMillis)
val item = CalendarEntity(date, id.toInt())
dao.insert(item)
start.add(Calendar.DAY_OF_MONTH, 1)
} while (start.timeInMillis <= end.timeInMillis)
}
}
This is the code that inserts the Todo created by the user through TodoDao, and inserts the value into CalendarDao from today to Date.END_OF_DAY (I randomly designated this value as "December 31, 2025"). But the insertion speed through CalendarDao was quite slow. There is no inconvenience in the UI, but if the user completely terminates the app from the task during insertion, it will be terminated without inserting data until the end. It has been said that using RxJava can solve this problem, how can you solve it? Even if it's not RxJava, if there is a way to solve this problem, please let me know.
Change Dispatchers.Default to Dispatchers.IO
This is a database operation and it should be handled on an IO thread, Default is a real heavy duty CPU thread.
Using RxJava is a good way to standardize your database interactions, it allows you to stay off the UI thread and setups up an Observer pattern to allow you to react to the data as you get it instead of waiting for it.
If they close the app while this operation is happening there is not much you can do, as this is handled under 1 transaction. As such the actual changes to the database are only handled at the end, meaning if the operation doesn't complete nothing gets inserted. But you also don't want to do this 1 transaction at a time because that is extremely slow. Its a reliability vs speed question.
I have some expensive operations that only need to be performed once (e.g. load/ download large files, load large ML models, or calculate optimized data structure based on some other data). I want to use this for every value the Observable/ Flowable generates:
The following code works, but it runs heavyProcessing() and heavyProcessing2() on the caller's thread. In my case, I can't choose what my callers thread (its the main thread because I am using WorkManager's RxWorker, which calls createWork from main). Therefore, start blocks the main thread. How do I get heavyProcessing to be performed in the background with RxJava and also available to the subsequent RxJava chain?
fun start(): Observable<Unit> {
val heavy = heavyProcessing() // the heavy value i want to use everywhere!
val anotherHeavyObject = heavyProcessing2()
val items = Observable.fromIterable(listOfHundredsOfItems)
.map { doSomeWork(it, heavy) }
.map { doSomeWork(it, anotherHeavyObject) }
}
My attempts has so far not worked:
Create a wrapper around the existing function: The issue with this code is the Observable returned by start() does not get observed, so the doSomeWork doesn't actually get done. I only know this because I put breakpoints in at doSomeWork, and it never gets called.
fun startInBackground(): Single<Unit> {
return Single.fromCallable {
start()
}
}
I've been trying to find ways of 'unnesting' the inner Observable (inside the Single), as that's probably the issue here. The inner Observable is not being observed.
This RxJava stuff is very unintuitive even after reading the guide
Yes, it was related to Deferred-dependent. The example in the docs state:
Sometimes, there is an implicit data dependency between the previous sequence and the new sequence that, for some reason, was not flowing through the "regular channels". One would be inclined to write such continuations as follows:
AtomicInteger count = new AtomicInteger();
Observable.range(1, 10)
.doOnNext(ignored -> count.incrementAndGet())
.ignoreElements()
.andThen(Single.defer(() -> Single.just(count.get())))
.subscribe(System.out::println);
Actually, all I needed the caller to do is:
Single.defer { start() }.map { doMoreWork() }
instead of
start().map { doMoreWork() }
I have a situation where I want to update an Activity's text fields as data comes in. The update only occurs when the simulation is completed, not while it is running (takes maybe 2 seconds to run).
Here is the code I have:
...
private var totalLoops = 0
private val updateDisplayTask = Runnable {
totalLoopsTV.text = totalLoops.toString()
totalEmailsSentTV.text = totalEmailsSent.toString()
totalPushesSentTV.text = totalPushesSent.toString()
private fun mainLoopFunction(currentTime: Long) {
...
totalLoops++
if(totalLoops % 20 == 0 || onDeckList.size == 0) {
Timber.w("UPDATING UI")
runOnUiThread(updateDisplayTask)
//handler.post(updateDisplayTask)
}
} //end of main loop
I've tried both runOnUiThread and handler/post as well as a few other things using Kotlin Coroutines, but nothing so far has worked. Can you see what I'm doing wrong here please? I see the logs of UPDATING UI so I know that the updates do get sent and I do see the last update (the only one I see) at the end.
Is this running on another thread, and then you run updateDisplayTask on the main thread? If you're updating totalLoops, totalEmailsSent and totalPushesSent on one thread (this worker thread) and reading them on another (main thread) then because of the way concurrency works, you might not actually see the new values on the main thread.
There are a few ways to manage synchronizing them, but if you're only writing the values on one thread (and you're not massively concerned about the possibility of some of the values changing partway through reading them, so they don't all match up) you can just use the #Volatile annotation on those variables to make them update across threads (works like the volatile keyword in Java).
If you care about atomic updates (everything changing together, can't read or write while something is in the middle of reading or writing them) you'll have to look into some kind of locking, like using synchronized methods and blocks. It's kind of a major (important!) subject, here's a post on it:
https://proandroiddev.com/synchronization-and-thread-safety-techniques-in-java-and-kotlin-f63506370e6d
so I've been looking at the coroutines for past few days and found quite interesting piece of code
val input = MutableStateFlow(5)
lifecycleScope.launch {
input.collectLatest {
val job = launch {
doSomething1()
delay(1000L)
doSomething2()
}
job.join()
}
}
I've been debugging it and im not sure why do we need that job.join in there, how I understand the whole flow right now:
Lets say we push fast 3 values to input, collectLatest will terminate previous unfinished box, but since we are launching new coroutine its job is not terminated, so after pushing fast 3 values we will always reach doSomething2 for each value, if we would skip launch inside collectLatest we would reach only one doSomething2 - but now coming to the job.join - it should suspend coroutine until the job is done, but since we are not doing anything else in this coroutine is it really needed? Does it give any value? From my tests it doesn't really matter if we have that job.join or not, what I am missing in here?
Im looking for an elegant way to run two observable's at the same time, wait for both to finish (They both fetch data from the web) and only once both have completed perform a function.
I also need to get a time difference between the two threads? Is there an elegant way to do this in RXJava, specifically for android. Or will i have to set a global timer variable in the oncomplete methods of both observable's and only compare them after?
My thinking is to merge the observeables into one, but then im not sure how to get the time difference?
You can zip the timestamped sequence of the two sources:
Observable<A> sourceA = ...
Observable<B> sourceB = ...
Observable.zip(sourceA.timestamp(), sourceB.timestamp(), (a, b) -> {
long timediff = a.time() - b.time();
A itemA = a.value();
B itemB = b.value();
return itemA + ", " + itemB;
})
.subscribe(...);