Hi guys, I have a question, in case i use async in...
# coroutines
g
Hi guys, I have a question, in case i use async inside a coroutinescope but I await it outside the scope is it ok to do so or is there something like a deadlock where the actual computation will happen inside the scope and the rest code will complete sequential no matter where I await for it ?
n
It's fine to
await
in a totally different context than the
async
lambda. Just be aware that the
coroutineScope
builder will not return until the result is ready because of structured concurrency. Seems like an odd thing to do to me. What’s the use case?
g
i just have a rest api and my guess is what if someone wants to open an async deeper in the call chain, is there any difference to actually accept the deferred and just await it just before i return back an apiResponse or is it ok to just wait immediately after he gives me the deferred or is it better if he does the awaiting and just give me back the result ?
n
You may want to provide some code snippets to clarify what you mean.
g
Hello allen, sorry for the late reply. I was wondering what is the actual difference between these three implementations
Copy code
@RestController
class TestApi {


    @GetMapping(value = ["test", "/test"])
    suspend fun test(response: ServerHttpResponse): FakeResponse = coroutineScope {
        val responseDeferred = async {
            return@async acceptResponse()
        }
        return@coroutineScope responseDeferred.await()
    }

    @GetMapping(value = ["test2", "/test2"])
    suspend fun test2(response: ServerHttpResponse): FakeResponse {

        val fakeResponseDeferred = acceptResponseAsync()

        return fakeResponseDeferred.await()
    }

    @GetMapping(value = ["test2", "/test2"])
    suspend fun test3(response: ServerHttpResponse): FakeResponse {

        val fakeResponseDeferred = acceptDeferredResponse()

        return fakeResponseDeferred
    }


    suspend fun acceptResponse(): FakeResponse {
        return FakeResponse("Hello From test")
    }

    suspend fun acceptResponseAsync(): Deferred<FakeResponse> = coroutineScope {
        async {
            return@async FakeResponse("Hello async From test")
        }
    }

    suspend fun acceptDeferredResponse(): FakeResponse = coroutineScope {
        async {
            return@async FakeResponse("Hello pretend we are doing some async heavy stuff")
        }
    }.await()

}
n
They are all the same.
coroutineScope
won't return until
async
is done. This is part of structured concurrency. Parent jobs don't finish until child jobs are all complete. So returning the
Deferred
outside of
coroutineScope
is pointless, since it is already complete. You can just return the value. The point of
coroutineScope
is so that you can launch multiple coroutines for concurrency inside a regular suspend method but still easily adhere to the principle that suspend methods finish all their work before they return. This is why
coroutineScope
waits for all children. If you want to return a
Deferred
that is not complete, then you should not use a suspend method and instead should use a non-suspend method that takes a
CoroutineScope
as a parameter (or as the receiver) and call
async/launch
on the provided
CoroutineScope
.
g
Interesting, really appreciate the pointers. Thanks !