Is it possible to execute a blocking coroutine call (one that returns a value) while also providing the thread to execute the call on (I don't want to use the main thread, which is the default)?
2 Answers
I suppose you are looking for async(context):
import kotlinx.coroutines.*
fun someCalc(): Int {
println(Thread.currentThread().name) // Prints different thread
Thread.sleep(500L)
return 42
}
fun main() {
val result = runBlocking {
val deferred = async(Dispatchers.Default) {
someCalc()
}
deferred.await()
}
println(result)
}
You can also use newSingleThreadContext() to create a context confined to a single thread and use it instead of Dispatchers.Default
EDIT: As @Rene said, there is a better solution:
val result = runBlocking {
withContext(Dispatchers.Default) {
someCalc()
}
}
4 Comments
Thread(), how would I execute the call on that specific thread using this method?val executor = Executors.newSingleThreadExecutor() val context = executor.asCoroutineDispatcher() and then use withContext(context) to start a coroutine and executor.execute() to start any code you want to launch in this thread.If you just have a thread that's already running, and you have no control over the code it runs, then there is nothing you can do about it. The thread must be running a top-level event loop so you can inject the code to run from the outside.
If, by any chance, you have this kind of control, or you can decide which Runnable the thread will run to begin with, here's some pretty hacky code that manages to set up an event loop and submit a coroutine to it:
val myContextFuture = CompletableFuture<CoroutineContext>()
thread(name = "my-thread") {
runBlocking {
myContextFuture.complete(coroutineContext)
coroutineContext[Job]!!.join()
}
}
val myContext = myContextFuture.get()
Here's how you would run a coroutine on myContext:
val result = withContext(myContext) {
println("Running on thread ${currentThread().name}")
3
}
println("Result of the coroutine: $result")
I wouldn't recommend using this kind of code in production.