I have a suspend function that looks something lik...
# coroutines
t
I have a suspend function that looks something like:
Copy code
suspend fun foo() {
    collection.forEach { element -> 
        withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
           // Some long running task processing 'element'
        }
    }
}
I'm wondering what would be the simplest way to parallelize the long running tasks (each element would be processed in parallel) I think this is what
async
might be for? It's just not something I've used so far, and I'm not sure what the syntax is..
d
Yes, you can use `async`:
Copy code
suspend fun foo(list: List<String>) {
    withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
        coroutineScope {
            val futures = list.map {
                async { it.uppercase() /* heavy computation here */ }
            }
            val results = futures.awaitAll()
        }
    }
}
t
Thanks. It looks like
Copy code
suspend fun foo(collection: List<Bar>) {
    collection.map { element -> 
        withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
            async {
               // Some long running task processing 'element'
            }
        }
    }.awaitAll()
}
Might be sufficient (no need to use an additional scope?)
d
ah yes of course,
withContext
has coroutineScope as well.
t
The actual implementation is a bit more complicated, so perhaps there's a mistake, but it seems this code still executes sequentially
d
awaitAll should definitely make it so it runs concurrently
t
I wonder if it's because I have a few more
withContext{}
inside the async (I'm trying to get back on the main thread to post messages to the UI)
d
Well the main thread is just that, one thread, so it will do its parts synchronously
t
Copy code
suspend fun foo(collection: List<Bar>) {
    collection.map { element -> 
        withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
            async {
               print("start of iteration ($element)")
               doSomeStuff()
               withContext(Dispatchers.Main) {
                   listener.notify()
               }
               doMoreStuff()
               print("end of iteration ($element)")
            }
        }
    }.awaitAll()
}
This prints something like "start of iteration (element 1)" "end of iteration (element 1)" "start of iteration (element 2)" "end of iteration (element 2)"
Maybe because
withContext()
 is a suspension point?
d
Yeah I think you want
async(<http://Dispatchers.IO|Dispatchers.IO>)
instead
t
Oh man, this gets confusing
The code actually is more like..
Copy code
suspend fun foo(collection: List<Bar>) {
    collection.map { element -> 
        withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
            async {
               print("start of iteration ($element)")
               doSomeStuff()
               withContext(Dispatchers.Main) {
                   listener.notify()
               }
               doMoreStuff()
               withContext(Dispatchers.Main) {
                   listener.notify()
               }
               doMoreStuff()
               withContext(Dispatchers.Main) {
                   listener.notify()
               }
               print("end of iteration ($element)")
            }
        }
    }.awaitAll()
}
If those are
async
instead of
withContext()
, then when do I call
await
on them?
The idea is I'm trying to report progress back to the UI, while the function continues to do its work
So
listener.notify()
needs to be called at the right time
Oh, I think I see the mistake
d
I think this is more akin to what you need:
Copy code
suspend fun foo(collection: List<Bar>) {
    coroutineScope {
        collection.map { element ->
            async(<http://Dispatchers.IO|Dispatchers.IO>) {
                print("start of iteration ($element)")
                doSomeStuff()
                withContext(Dispatchers.Main) {
                }
                doMoreStuff()
                withContext(Dispatchers.Main) {
                }
                doMoreStuff()
                withContext(Dispatchers.Main) {
                }
                print("end of iteration ($element)")
            }
        }.awaitAll()
    }
}
👍 1
t
Copy code
suspend fun foo(collection: List<Bar>) {
    collection.map { element -> 
        withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
            async {
Should be
Copy code
suspend fun foo(collection: List<Bar>) {
    withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
        collection.map { element -> 
            async {
Thanks for your help
z
If you don’t need results from the coroutines, use
launch
instead of
async
and
join
instead of
await
.
👍 2
t
Ok, thanks