Launch two coroutines and wait for single result - kotlin

I wonder if there is any other way to launch two coroutines and return result from faster one.
I've done it using channelFlow, but I think there might be some other solution.
suspend fun execute(): Result {
return channelFlow {
listOf(
coroutineScope.async { send(firstCourotine()) },
coroutineScope.async { send(secondCourotine()) }
).awaitAll()
}.first().also { cancel() }
}

You can use a select expression for that, making execute a CoroutineScope extension function:
suspend fun CoroutineScope.execute(): Result {
val list = listOf(
async { firstCourotine() },
async { secondCourotine() }
)
return select {
list.forEach {
it.onAwait { answer ->
answer
}
}
}
}
You should call execute in a scope that you can cancel in order to stop all its active coroutines as soon as you receive the result:
...
val scope = CoroutineScope(Dispatchers.Default)
val result = scope.async {
val res = execute()
coroutineContext.cancelChildren()
res
}.await()
//Do something with 'result' here
...
NOTE: select expression is in experimental state.
You can find select expression official documentation here.

Related

How can I get a previous emission Kotlin Flow?

Let me use a simple image to illustrate what I want to get:
I don't want to use SharedFlow's replayCache to achieve this because if a new observer observes that SharedFlow, it will get 2 emissions instead of one latest emission.
Or if I write it in code:
val sharedFlow = MutableSharedFlow(replay = 1)
val theFlowThatIWant = sharedFlow.unknownOperator { … }
sharedFlow.emit(1)
sharedFlow.emit(2)
sharedFlow.collect {
println(it)
}
Expected output:
2
theFlowThatIWant.collect {
println(it)
}
Expected output:
1
We can create such operator by ourselves. We can generalize it to more items than only the last one and use circular buffer to keep postponed items:
suspend fun main() {
val f = flow {
repeat(5) {
println("Emitting $it")
emit(it)
delay(1000)
}
}
f.postponeLast()
.collect { println("Collecting $it") }
}
fun <T> Flow<T>.postponeLast(count: Int = 1): Flow<T> = flow {
val buffer = ArrayDeque<T>(count)
collect {
if (buffer.size == count) {
emit(buffer.removeFirst())
}
buffer.addLast(it)
}
}
Note that this solution never emits postponed items. If you like to emit them at the end, just add this after collect { }:
while (buffer.isNotEmpty()) {
emit(buffer.removeFirst())
}

Kotlin async processing with optional async dependencies

I have a function that conditionally fetches some data and runs some tasks concurrently on that data. Each task depends on different sets of data and I would like to avoid fetching the data that's not needed. Moreover, some of the data can have already been prefetched and given to the function. See the code I've come up with below.
suspend fun process(input: SomeInput, prefetchedDataX: DataX?, prefetchedDataY: DataY?) = coroutineScope {
val dataXAsync = lazy {
if (prefetchedDataX == null) {
async { fetchDataX(input) }
} else CompletableDeferred(prefetchedDataX)
}
val dataYAsync = lazy {
if (prefetchedDataY == null) {
async { fetchDataY(input) }
} else CompletableDeferred(prefetchedDataY)
}
if (shouldDoOne(input)) launch {
val (dataX, dataY) = awaitAll(dataXAsync.value, dataYAsync.value)
val modifiedDataX = modifyX(dataX)
val modifiedDataY = modifyY(dataY)
doOne(modifiedDataX, modifiedDataY)
}
if (shouldDoTwo(input)) launch {
val modifiedDataX = modifyX(dataXAsync.value.await())
doTwo(modifiedDataX)
}
if (shouldDoThree(input)) launch {
val modifiedDataY = modifyY(dataYAsync.value.await())
doThree(modifiedDataY)
}
}
Any improvements that could be made to this code? One, I don't like having to fakely wrap the prefetched data into a CompletableDeferred. Two, I don't like having to call modifyX, modifyY inside each task, I wish I could apply it at the fetching stage, but I haven't come up with a nice way to do that. Alternatively I could do
val modifiedDataXAsync = lazy {
async { modifyX(prefetchedDataX ?: fetchDataX(input)) }
}
but it feels wasteful to be spawning a new coroutine when the data is already prefetched. Am I over-optimizing?
How about this? This code is pretty similar to yours, I just simplified it a bit.
suspend fun process(input: SomeInput, prefetchedDataX: DataX?, prefetchedDataY: DataY?) = coroutineScope {
val modifiedDataX by lazy {
async { modifyX(prefetchedDataX ?: fetchDataX(input)) }
}
val modifiedDataY by lazy {
async { modifyY(prefetchedDataY ?: fetchDataY(input)) }
}
if (shouldDoOne(input)) launch {
val (dataX, dataY) = awaitAll(modifiedDataX, modifiedDataY)
doOne(dataX, dataY)
}
if (shouldDoTwo(input)) launch {
doTwo(modifiedDataX.await())
}
if (shouldDoThree(input)) launch {
doThree(modifiedDataY.await())
}
}

How to write rx concatArrayEager equivalent in Kotlin CoRoutine?

I would like to convert my rxJava Code to Kotlin CoRoutine.
Below is the code makes both the api and db call and returns the data to UI whatever comes first. Let us say if DB response happens to be quicker than the api. In that case still, the api response would continue until it receives the data to sync with db though it could have done the UI update earlier.
How Would I do it?
class MoviesRepository #Inject constructor(val apiInterface: ApiInterface,
val MoviesDao: MoviesDao) {
fun getMovies(): Observable<List<Movie>> {
val observableFromApi = getMoviesFromApi()
val observableFromDb = getMoviesFromDb()
return Observable.concatArrayEager(observableFromApi, observableFromDb)
}
fun getMoviesFromApi(): Observable<List<Movie>> {
return apiInterface.getMovies()
.doOnNext { it ->
it.data?.let { it1 -> MoviesDao.insertAllMovies(it1) }
println("Size of Movies from API %d", it.data?.size)
}
.map({ r -> r.data })
}
fun getMoviesFromDb(): Observable<List<Movie>> {
return MoviesDao.queryMovies()
.toObservable()
.doOnNext {
//Print log it.size :)
}
}
}
As the first step you should create suspend funs for your ApiInterface and MovieDao calls. If they have some callback-based API, you can follow these official instructions.
You should now have
suspend fun ApiInterface.suspendGetMovies(): List<Movie>
and
suspend fun MoviesDao.suspendQueryMovies(): List<Movie>
Now you can write this code:
launch(UI) {
val fromNetwork = async(UI) { apiInterface.suspendGetMovies() }
val fromDb = async(UI) { MoviesDao.suspendQueryMovies() }
select<List<Movie>> {
fromNetwork.onAwait { it }
fromDb.onAwait { it }
}.also { movies ->
// act on the movies
}
}
The highlight is the select call which will simultaneously await on both Deferreds and act upon the one that gets completed first.
If you want to ensure you act upon the result from the network, you'll need some more code, for example:
val action = { movies: List<Movie> ->
// act on the returned movie list
}
var gotNetworkResult = false
select<List<Movie>> {
fromNetwork.onAwait { gotNetworkResult = true; it }
fromDb.onAwait { it }
}.also(action)
if (!gotNetworkResult) {
action(fromNetwork.await())
}
This code will act upon the DB results only if they come in before the network results, which it will process in all cases.
Something along those lines should work:
data class Result(val fromApi: ???, val fromDB: ???)
fun getMovies(): Result {
val apiRes = getMoviesFromApiAsync()
val dbRes = getMoviesFromDbAsync()
return Result(apiRes.await(), dbRes.await())
}
fun getMoviesFromApiAsync() = async {
return apiInterface.getMovies()
.doOnNext { it ->
it.data?.let { it1 -> MoviesDao.insertAllMovies(it1) }
println("Size of Movies from API %d", it.data?.size)
}
.map({ r -> r.data })
}
fun getMoviesFromDbAsync() = async {
return MoviesDao.queryMovies()
}
I don't know what you're returning, so I just put ??? instead.

How would I "wrap" this not-quite-"by lazy" result caching function call in idiomatic Kotlin?

I can't use "by lazy" because the callbacks require suspendCoroutine, which borks in android if it blocks the main thread, so I have to use the following "cache the result" pattern over and over. Is there a way to wrap it in a funButUseCachedResultsIfTheyAlreadyExist pattern to encapsulate the xCached object?
private var cameraDeviceCached: CameraDevice? = null
private suspend fun cameraDevice(): CameraDevice {
cameraDeviceCached?.also { return it }
return suspendCoroutine { cont: Continuation<CameraDevice> ->
... deep callbacks with cont.resume(camera) ...
}.also {
cameraDeviceCached = it
}
}
When what I'd really like to write is
private suspend fun cameraDevice(): CameraDevice = theMagicFunction { cont ->
... deep callbacks with cont.resume(camera) ...
}
You can build a generalized solution by wrapping an async call as follows:
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineStart.LAZY
class LazySuspendFun<out T>(
scope: CoroutineScope,
private val block: suspend () -> T
) {
private val deferred = scope.async(Dispatchers.Unconfined, LAZY) { block() }
suspend operator fun invoke() = deferred.await()
}
fun <T> CoroutineScope.lazySuspendFun(block: suspend () -> T) =
LazySuspendFun(this, block)
This is a simple example of how you can use it. Note that we are able to compose them so that we use a lazy-inited value as a dependency to getting another one:
val fetchToken = lazySuspendFun<String> {
suspendCoroutine { continuation ->
Thread {
info { "Fetching token" }
sleep(3000)
info { "Got token" }
continuation.resume("hodda_")
}.start()
}
}
val fetchPosts = lazySuspendFun<List<String>> {
val token = fetchToken()
suspendCoroutine { continuation ->
Thread {
info { "Fetching posts" }
sleep(3000)
info { "Got posts" }
continuation.resume(listOf("${token}post1", "${token}post2"))
}
}
}
On the calling side you must be inside some coroutine context so you can call the suspending functions:
myScope.launch {
val posts = fetchPosts()
...
}
This solution is robust enough that you can concurrently request the value several times and the initializer will run only once.
I'll write this as an answer, since it's not possible to post much code in comments.
What you're looking for is something like this:
private suspend fun cameraDevice() = theMagicFunction {
CameraDevice()
}()
suspend fun theMagicFunction(block: ()->CameraDevice): () -> CameraDevice {
var cameraDeviceCached: CameraDevice? = null
return fun(): CameraDevice {
cameraDeviceCached?.also { return it }
return suspendCoroutine { cont: Continuation<CameraDevice> ->
cont.resume(block())
}.also {
cameraDeviceCached = it
}
}
}
Unfortunately, this will not compile, since closures cannot be suspendable, and neither are local functions.
Best I can suggest, unless I miss a solution there, is to encapsulate this in a class, if this variable bothers you too much.

Returning a value produced in Kotlin coroutine

I am trying to return a value generated from coroutine
fun nonSuspending (): MyType {
launch(CommonPool) {
suspendingFunctionThatReturnsMyValue()
}
//Do something to get the value out of coroutine context
return somehowGetMyValue
}
I have come up with the following solution (not very safe!):
fun nonSuspending (): MyType {
val deferred = async(CommonPool) {
suspendingFunctionThatReturnsMyValue()
}
while (deferred.isActive) Thread.sleep(1)
return deferred.getCompleted()
}
I also thought about using event bus, but is there a more elegant solution to this problem?
Thanks in advance.
You can do
val result = runBlocking(CommonPool) {
suspendingFunctionThatReturnsMyValue()
}
to block until the result is available.
You can use this:
private val uiContext: CoroutineContext = UI
private val bgContext: CoroutineContext = CommonPool
private fun loadData() = launch(uiContext) {
try {
val task = async(bgContext){dataProvider.loadData("task")}
val result = task.await() //This is the data result
}
}catch (e: UnsupportedOperationException) {
e.printStackTrace()
}
}