Reputation: 9947
I have a collection and I want to execute some operations on all items of it asynchronously in Kotlin.
I can do this easily with two map operations:
suspend fun collectionAsync() = coroutineScope {
val list = listOf("one", "two", "three")
list.map { async { callRemoteService(it) } }.map { it.await() }.forEach { println(it) }
}
suspend fun callRemoteService(input: String): String
{
delay(1000)
return "response for $input"
}
What I would like to have is something like this:
asyncAll(list, ::callRemoteService).awaitAll()
I probably could implement it with extension functions. I'm just wondering if there is a more idiomatic way of doing this.
EDIT: I found that awaitAll already exists. Now, I just need an asyncAll.
list.map { async { callRemoteService(it) } }.awaitAll().forEach { println(it) }
EDIT2: I wrote my asyncAll implementation:
fun <T, V> CoroutineScope.asyncAll(
items: Iterable<T>,
function: suspend (T) -> V
): List<Deferred<V>>
{
return items.map { async { function.invoke(it) } }
}
So now I have this which looks pretty good:
asyncAll(list) { callRemoteService(it) }.awaitAll()
Now, I'm just wondering if it is something that already exists :)
EDIT3: Thinking about it, this might even could look better:
list.asyncAll { callRemoteService(it) }.awaitAll()
I'm just having trouble with the implementation. Since I already have a receiver here which is the iterable, I'm not sure how I could pass the couroutine scope:
fun <T, V> Iterable<T>.asyncAll(
function: (T) -> V
): List<Deferred<V>>
{
return this.map { async { function.invoke(it) } }
}
Upvotes: 4
Views: 6082
Reputation: 9947
Finally, got the solution I wanted. I need this extension function:
suspend fun <T, V> Iterable<T>.asyncAll(coroutine: suspend (T) -> V): Iterable<V> = coroutineScope {
[email protected] { async { coroutine(it) } }.awaitAll()
}
and I can use it like this:
list.asyncAll { callRemoteService(it) }.forEach { println(it) }
I'm not sure about the naming. It could be asyncMap
as well.
Upvotes: 7