Kotlin/Native: How to perform blocking calls asynchronously? - kotlin

As of now, Kotlin/Native is single-threaded. Therefore, the following code will become blocked by sleep:
coroutineScope {
launch { plaform.posix._sleep(100000) }
launch { println("Hello") }
}
However, it has a novel concurrency mechanism called Workers. Yet, even with worker the main thread is going to be blocked by long-running posix call:
coroutineScope {
launch { Worker.start().execute(TransferMode.SAFE, { }, { plaform.posix._sleep(100000) }).consume{ } }
launch { println("Hello") }
}
Both of the snippets above will never print Hello.
What is the correct way to perform a series of expensive blocking calls asynchronously?

There is a multithreaded version of kotlin coroutines for K/N, which lives on a separate branch currently: native-mt.
You could use Dispatchers.Default to offload tasks to the background thread

So, the problem is that I used the consume method, which blocks the main thread.
Instead, you need to execute the worker, and then check manually whether it finished:
val job = Worker.start().execute(TransferMode.SAFE, { }) { plaform.posix._sleep(100000) }
...
if (job.state == FutureState.Computed)
job.result

Related

How to cancel kotlin coroutine with potentially "un-cancellable" method call inside it?

I have this piece of code:
// this method is used to evaluate the input string, and it returns evaluation result in string format
fun process(input: String): String {
val timeoutMillis = 5000L
val page = browser.newPage()
try {
val result = runBlocking {
withTimeout(timeoutMillis) {
val result = page.evaluate(input).toString()
return#withTimeout result
}
}
return result
} catch (playwrightException: PlaywrightException) {
return "Could not parse template! '${playwrightException.localizedMessage}'"
} catch (timeoutException: TimeoutCancellationException) {
return "Could not parse template! (timeout)"
} finally {
page.close()
}
}
It should throw exception after 5 seconds if the method is taking too long to execute (example: input potentially contains infinite loop) but it doesent (becomes deadlock I assume) coz coroutines should be cooperative. But the method I am calling is from another library and I have no control over its computation (for sticking yield() or smth like it).
So the question is: is it even possible to timeout such coroutine? if yes, then how?
Should I use java thread insted and just kill it after some time?
But the method I am calling is from another library and I have no control over its computation (for sticking yield() or smth like it).
If that is the case, I see mainly 2 situations here:
the library is aware that this is a long-running operation and supports thread interrupts to cancel it. This is the case for Thread.sleep and some I/O operations.
the library function really does block the calling thread for the whole time of the operation, and wasn't designed to handle thread interrupts
Situation 1: the library function is interruptible
If you are lucky enough to be in situation 1, then simply wrap the library's call into a runInterruptible block, and the coroutines library will translate cancellation into thread interruptions:
fun main() {
runBlocking {
val elapsed = measureTimeMillis {
withTimeoutOrNull(100.milliseconds) {
runInterruptible {
interruptibleBlockingCall()
}
}
}
println("Done in ${elapsed}ms")
}
}
private fun interruptibleBlockingCall() {
Thread.sleep(3000)
}
Situation 2: the library function is NOT interruptible
In the more likely situation 2, you're kind of out of luck.
Should I use java thread insted and just kill it after some time?
There is no such thing as "killing a thread" in Java. See Why is Thread.stop deprecated?, or How do you kill a Thread in Java?.
In short, in that case you do not have a choice but to block some thread.
I do not know a solution to this problem that doesn't leak resources. Using an ExecutorService would not help if the task doesn't support thread interrupts - the threads will not die even with shutdownNow() (which uses interrupts).
Of course, the blocked thread doesn't have to be your thread. You can technically launch a separate coroutine on another thread (using another dispatcher if yours is single-threaded), to wrap the libary function call, and then join() the job inside a withTimeout to avoid waiting for it forever. That is however probably bad, because you're basically deferring the problem to whichever scope you use to launch the uncancellable task (this is actually why we can't use a simple withContext here).
If you use GlobalScope or another long-running scope, you effectively leak the hanging coroutine (without knowing for how long).
If you use a more local parent scope, you defer the problem to that scope. This is for instance the case if you use the scope of an enclosing runBlocking (like in your example), which makes this solution pointless:
fun main() {
val elapsed = measureTimeMillis {
doStuff()
}
println("Completely done in ${elapsed}ms")
}
private fun doStuff() {
runBlocking {
val nonCancellableJob = launch(Dispatchers.IO) {
uncancellableBlockingCall()
}
val elapsed = measureTimeMillis {
withTimeoutOrNull(100.milliseconds) {
nonCancellableJob.join()
}
}
println("Done waiting in ${elapsed}ms")
} // /!\ runBlocking will still wait here for the uncancellable child coroutine
}
// Thread.sleep is in fact interruptible but let's assume it's not for the sake of the example
private fun uncancellableBlockingCall() {
Thread.sleep(3000)
}
Outputs something like:
Done waiting in 122ms
Completely done in 3055ms
So the bottom line is either live with this long thing potentially hanging, or ask the developers of that library to handle interruption or make the task cancellable.

Coroutine launch() while inside another coroutine

I have the following code (pseudocode)
fun onMapReady()
{
//do some stuff on current thread (main thread)
//get data from server
GlobalScope.launch(Dispatchers.IO){
getDataFromServer { result->
//update UI on main thread
launch(Dispatchers.Main){
updateUI(result) //BREAKPOINT HERE NEVER CALLED
}
}
}
}
As stated there as a comment, the code never enters the coroutine dispatching onto main queue. The below however works if I explicitly use GlobalScope.launch(Dispatchers.Main) instead of just launch(Dispatchers.Main)
fun onMapReady()
{
//do some stuff on current thread (main thread)
//get data from server
GlobalScope.launch(Dispatchers.IO){
getDataFromServer { result->
//update UI on main thread
GlobalScope.launch(Dispatchers.Main){
updateUI(result) //BREAKPOINT HERE IS CALLED
}
}
}
}
Why does the first approach not work?
I believe the problem here is that getDataFromServer() is asynchronous, it immediately returns and therefore you invoke launch(Dispatchers.Main) after you exited from the GlobalScope.launch(Dispatchers.IO) { ... } block. In other words: you try to start a coroutine using a coroutine scope that has finished already.
My suggestion is to not mix asynchronous, callback-based APIs with coroutines like this. Coroutines work best with suspend functions that are synchronous. Also, if you prefer to execute everything asynchronously and independently of other tasks (your onMapReady() started 3 separate asynchronous operations) then I think coroutines are not at all a good choice.
Speaking about your example: are you sure you can't execute getDataFromServer() from the main thread directly? It shouldn't block the main thread as it is asynchronous. Similarly, in some libraries callbacks are automatically executed in the main thread and in such case your example could be replaced with just:
fun onMapReady() {
getDataFromServer { result->
updateUI(result)
}
}
If the result is executed in a background thread then you can use GlobalScope.launch(Dispatchers.Main) as you did, but this is not really the usual way how we use coroutines. Or you can use utilities like e.g. runOnUiThread() on Android which probably makes more sense.
#broot already explained the gist of the problem. You're trying to launch a coroutine in the child scope of the outer GlobalScope.launch, but that scope is already done when the callback of getDataFromServer is called.
So in short, don't capture the outer scope in a callback that will be called in a place/time that you don't control.
One nicer way to deal with your problem would be to make getDataFromServer suspending instead of callback-based. If it's an API you don't control, you can create a suspending wrapper this way:
suspend fun getDataFromServerSuspend(): ResultType = suspendCoroutine { cont ->
getDataFromServer { result ->
cont.resume(result)
}
}
You can then simplify your calling code:
fun onMapReady() {
// instead of GlobalScope, please use viewModelScope or lifecycleScope,
// or something more relevant (see explanation below)
GlobalScope.launch(Dispatchers.IO) {
val result = getDataFromServer()
// you don't need a separate coroutine, just a context switch
withContext(Dispatchers.Main) {
updateUI(result)
}
}
}
As a side note, GlobalScope is probably not what you want, here. You should instead use a scope that maps to the lifecycle of your view or view model (viewModelScope or lifecycleScope) because you're not interested in the result of this coroutine if the view is destroyed (so it should just be cancelled). This will avoid coroutine leaks if for some reason something hangs or loops inside the coroutine.

Parallel requests with coroutines

I'm trying to fetch some data from multiple locations to fill a recyclerView. I used to use callbacks, which worked fine, but need to refactor it to coroutines.
So i have a list of retrofit services and call each on of them parallerl. Then i can update the recyclerView with the onResponse callback. How can i achive this with coroutines.
I tried something like that, but the next call is fired after i got a response:
runblocking {
for (service in services) {
val response = async(Dispatchers.IO) {
service.getResponseAsync()
}
adapter.updateRecyclerView(response.await())
}
}
With another approach i had the problem that i was not able to get back on the main thread to update my ui as i was using launch and could not await the response:
runblocking {
services.foreach {
launch(Dispatcher.IO) {
val response = it.getResponseAsync()
}
withContext(Dispatcher.Main) {
adapter.updateRecyclerView(response)
}
}
}
I'm thankfull for every tip ;)
cheers patrick
Start coroutines with launch instead of runBlocking. The examples below assume you're launching from a context that uses Dispatchers.Main by default. If that's not the case, you could use launch(Dispatchers.Main) for these.
If you want to update your view every time any of the parallel actions returns, then move your UI update inside the coroutines that you're launching for each of the service items:
for (service in services) {
launch {
val response = withContext(Dispatchers.IO) { service.getResponseAsync() }
adapter.updateRecyclerView(response)
}
}
If you only need to update once all of them have returned, you can use awaitAll. Here, your updateRecyclerView function would have to be written to handle a list of responses instead of one at a time.
launch {
val responses = services.map { service ->
async(Dispatchers.IO) { service.getResponseAsync() }
}
adapter.updateRecyclerView(responses.awaitAll())
}
The await() call suspends the current coroutine and frees the current thread for being attached by other queued coroutines.
So when await() is called the current coroutine suspends till the response is received, and that's why for loop does not complete (goes to next iteration before completion of before request).
First and foremost you should not be using the runBlocking here, it is highly discouraged to be used in production evironment.
You should instead be using the ViewModel scope provided by android for structured concurrency (cancels the request if no longer needed like if lifecycle of activity is over).
You can use view model scope like this in activity or fragment viewModelOwner.viewModelScope.launch(/*Other dispatcher if needed*/) {} or make a coroutine scope yourself with a job attached which cancels itself on onDestroy.
For the problem the coroutine does not do parallel requests, you can launch multiple request without await (ing) on them inside the for loop.
And select them, using select expression https://kotlinlang.org/docs/reference/coroutines/select-expression.html#selecting-deferred-values
Example:
viewModelOwner.viewModelScope.launch {
val responses = mutableListOf<Deferred<TypeReturnedFromGetResponse>>()
for (service in services) {
async(Dispatchers.IO) {
service.getResponseAsync()
}.let(responses::add)
}
// adds which ever request is done first in oppose to awaiting for all then update
for (i in responses.indices) {
select<Unit> {
for (response in responses) {
response.onAwait {
adapter.updateRecyclerView(it)
}
}
}
}
}
PS: Using this method looks ugly but will update the adapter as soon as whichever request is first resolved, instead of awaiting for each and every request and then updating the items in it.

Kotlin: How to delay code in Android without making the UI freeze

I am trying to delay code in Kotlin I have tried
Thread.sleep(1000)
But its freezes the UI.
Does somebody know why this is happening
And how to delay without freezing the UI?
What went wrong
Usage Thread.sleep(...)
Thread.sleep causes the current thread to suspend execution for a specified period. This is an efficient means of making processor time available to the other threads of an application or other applications that might be running on a computer system.
For the OP (Original Poster / Asker)'s clarification:
It freezes the UI, does somebody know why this is happening?
As mentioned above from the official documentation of Java, you are experiencing a some sort of freezing in the UI because you have called it in the Main Thread.
Main Thread or if you are doing your stuff in Android, it is often called the UI Thread:
On the Android platform, applications operate, by default, on one thread. This thread is called the UI thread. It is often called that because this single thread displays the user interface and listens for events that occur when the user interacts with the app.
Without using the help of multi-threading APIs (Such as Runnable, Coroutines, RxJava), you will automatically be invoking Thread.sleep(1000) on the UI Thread that is why you are experiencing such "UI Freezing" experience because, other UI Operations are blocked from accessing the thread since you have invoke a suspension on it.
And how to delay without freezing the ui?
Harness the power of available APIs for multi-threading, so far it's good to start with the following options:
1. Runnable
In Java
// Import
import android.os.Handler;
// Use
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
// do something after 1000ms
}
}, 1000);
In Kotlin
// Import
import android.os.Handler;
// Use
val handler = Handler()
handler.postDelayed({
// do something after 1000ms
}, 1000)
2. Kotlin Coroutines
// Import
import java.util.*
import kotlin.concurrent.schedule
// Use
Timer().schedule(1000){
// do something after 1 second
}
3. RxJava
// Import
import io.reactivex.Completable
import java.util.concurrent.TimeUnit
// Use
Completable
.timer(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io()) // where the work should be done
.observeOn(AndroidSchedulers.mainThread()) // where the data stream should be delivered
.subscribe({
// do something after 1 second
}, {
// do something on error
})
Amongst the three, currently, RxJava is the way to go for multi threading and handling vast amount of data streams in your application. But, if you are just starting out, it is good to try out the fundamentals first.
References
https://docs.oracle.com/javase/tutorial/essential/concurrency/sleep.html
https://www.intertech.com/Blog/android-non-ui-to-ui-thread-communications-part-1-of-5/
https://github.com/ReactiveX/RxJava
https://github.com/Kotlin/kotlinx.coroutines
You can use Handler object https://developer.android.com/reference/android/os/Handler.
val handler = Handler()
val runnable = Runnable {
// code which will be delayed
}
handler.postDelayed(runnable, 1000)
1000 is time in miliseconds, you should replace it with your value.
If you don't want to freeze the UI, you need to execute your code off of the MainThread.
There are a lot of way of doing it. Some examples:
Thread
Thread {
Thread.sleep(1000)
// Your code
}.start()
Rx
You need https://github.com/ReactiveX/RxJava
Flowable.timer(1000, TimeUnit.MILLISECONDS)
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe {
// Your code
}
Kotlin coroutine
GlobalScope.launch { // launch new coroutine in background and continue
delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
println("World!") // print after delay
}
reference: https://kotlinlang.org/docs/reference/coroutines-overview.html
Documentations:
https://developer.android.com/guide/components/processes-and-threads
https://developer.android.com/topic/performance/threads
https://developer.android.com/training/multiple-threads/communicate-ui
if you are looking at delaying the code on a background thread and update the UI later kotlin coroutines come in handy check below
Timer().schedule(2000){
CoroutineScope(Main).launch {
withContext(Main){
//run UI related code
//will be executed after the timeout
}
}
}
GlobalSocpe.launch(Dispatchers.MAIN){
delay(5000)
}
this is the code part you asked for. But for your solution, first understand
launch
and
async
Similarly you should understand other values of
Dispatchers
Kotlin
Delayed code on UI Thread with Coroutines from a Fragment
Timer().schedule(1000) {
activity?.runOnUiThread {
// do something after 1000ms
}
}
If you get this Exception
java.lang.IllegalStateException: Method
setCurrentState must be called on the main thread
Handler is Deprecated
Thread.sleep(1000);
Causes the currently executing thread to sleep (temporarily cease
execution) for the specified number of milliseconds, [...]
see https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#sleep(long)
If you call this on the UI thread, which is the default thread your code runs on, it will stop and wait.
In pure Kotlin you should use a coroutine:
import kotlinx.coroutines.*
fun main() {
GlobalScope.launch { // launch new coroutine in background and continue
delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
println("World!") // print after delay
}
println("Hello,") // main thread continues while coroutine is delayed
Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}
If you are programming an Android app you can use a Handler and Androidx for especially nice syntax:
Handler().postDelayed( 1000 ) { doSomething() }
Use this extension:
//extension:
fun GlobalScope.runDelayedUITask(delay: Long, task: () -> Unit) {
launch(Dispatchers.IO) {
delay(delay)
launch(Dispatchers.Main) {
task()
}
}
}
//usage:
GlobalScope.runDelayedUITask(1000) {
//Your task...
}

Kotlin Coroutines with timeout

I'm currently writing a test-function which should run a block or (when a certain timeout is reached) throws an exception.
I was trying this with Coroutines in Kotlin but ended up with a mixture of Coroutines and CompletableFuture:
fun <T> runBlockWithTimeout(maxTimeout: Long, block: () -> T ): T {
val future = CompletableFuture<T>()
// runs the coroutine
launch { block() }
return future.get(maxTimeout, TimeUnit.MILLISECONDS)
}
This works, but I'm not sure if this is the intended way to solve that problem in kotlin.
I also tried other approaches:
runBlocking {
withTimeout(maxTimeout) {
block()
}
}
But this seems not to work as soon as the block calls e.g. Thread.sleep(...)
So is the CompletableFuture approach the way to go or is there a better one?
update 1
What I want to achieve:
Async Integration-Test code (like receiving data from RabbitMq) should be tested somehow like this:
var rabbitResults: List = ... // are filled async via RabbitListeners
...
waitMax(1000).toSucceed {
assertThat(rabbitResults).hasSize(1)
}
waitMax(1000).toSucceed {
assertThat(nextQueue).hasSize(3)
}
...
withTimeout { ... } is designed to cancel the ongoing operation on timeout, which is only possible if the operation in question is cancellable.
The reason it works with future.get(timeout, unit) is because it only waits with timeout. It does not actually cancel or abort in any way your background operation which still continues to execute after timeout had elapsed.
If you want to mimick similar behavior with coroutines, then you should wait with timeout, like this:
val d = async { block() } // run the block code in background
withTimeout(timeout, unit) { d.await() } // wait with timeout
It works properly because await is a cancellable function which you can verify by reading its API documentation.
However, if you want to actually cancel the ongoing operation on timeout, then then you should implement your code in asyncronous and cancellable way. Cancellation is cooperative, so, to start, the underlying library that you are using in your code has to provide asynchronous API that supports cancellation of ongoing operation.
You can read more about cancellation and timeouts in the corresponding section of the coroutines guide and watch the KotlinConf's Deep Dive into Coroutines on how to integrate coroutines with asynchronous libraries.