https://kotlinlang.org/docs/composing-suspending-functions.html
์ ๋งํฌ๋ฅผ ๊ณต๋ถํ๋ฉฐ ๋จ๊ธฐ๋ ๊ธฐ๋ก์ด๋ค.
fun main() = runBlocking<Unit> {
val time = measureTimeMillis {
val one = doSomethingUsefulOne()
val two = doSomethingUsefulTwo()
println("The answer is ${one + two}")
}
println("Completed in $time ms")
}
suspend fun doSomethingUsefulOne(): Int {
delay(1000L) // pretend we are doing something useful here
return 13
}
suspend fun doSomethingUsefulTwo(): Int {
delay(1000L) // pretend we are doing something useful here, too
return 29
}
๋ถ๋ชจ ์ฝ๋ฃจํด ์ค์ฝํ์ ์คํ์๊ฐ์ ์์ ์ค์ฝํ์ ์คํ์๊ฐ๋ ๋ชจ๋ ํฌํจํ๋ค. measureTimeMillis๋ ๋ด๋ถ ๊ตฌ๋ฌธ ์คํ์๊ฐ์ ๋ฐํํ๋ ํจ์๋ค.
Async
์ ์ฝ๋๋ ๋ suspend fun๊ณผ ์ฝ๋ฃจํด ๋ด๋ถ ์ฝ๋๊ฐ ์์๋๋ก ๋์๊ฐ๋ค. ๋ฐ๋ผ์ ์คํ์๊ฐ์ด ์ฝ 2000ms์ผ๋ก ์กํ๋ค. ์ด๊ฑธ ์ํ์ง์๋ ๊ฒฝ์ฐ๊ฐ ์์ํ ๋ฐ async๋ฅผ ์ฌ์ฉํด ์กฐ์ํ๋ ๋ฐฉ๋ฒ์ด ์๋ค. async๋ฅผ ์ฌ์ฉํ๋ฉด launch์ ๊ฐ์ด ์ฝ๋ฃจํด์ ์์ฑํ๋ ์ญํ ์ ํ๊ธฐ ๋๋ฌธ์ ๋์์ ์๋์ํฌ์ ์๋ค๋ ์ฅ์ ์ด ์๊ณ launch๋ ๊ฐ์ ๋ฐํํ๋ ์๊ธฐ๋ฅผ ์กฐ์ ํ์ง ๋ชปํ์ง๋ง async๋ await()๋ฅผ ์ด์ฉํด์ ์ฐ์ฐ์๊ธฐ๋ฅผ ์กฐ์ ํ ์ ์๋ค๋ ์ฅ์ ์ด ์๋ค.
val time = measureTimeMillis {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")
์ด ์ฝ๋์ ์คํ์๊ฐ์ ์ฝ 1000ms์ด๋ค.
fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T>
async์ ๊ตฌ์กฐ์ธ๋ฐ Deferred ์ธํฐํ์ด์ค๋ฅผ ์์๋ฐ์ ์ฌ์ฉํ๋ค. ์ด๊ฑด Job๊ณผ ๋์ผํ๊ฒ ์๋ํ๋ฉฐ cancellableํ๋ค.
CoroutineStart.LAZY
val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
one.start()
two.start()
async์ ํ๋ผ๋ฏธํฐ์๋ start๊ฐ ์๋ค. ์ด ํ๋ผ๋ฏธํฐ๋ฅผ CoroutineStart.LAZY๋ก ์ง์ ํ๋ฉด lazilyํ๊ฒ ์ฝ๋ฃจํด์ ์คํํ๊ฒ ๋๋๋ฐ ์ด ๊ฒฝ์ฐ ์๋ active ์ํ๋ฅผ ๋ฐํํ๋ Deferred๊ฐ new ์ํ๋ฅผ ๋ฐํํ๊ฒ ๋๋ค. new ์ํ๋ก ๋ง๋ค์ด์ง ์ด Deferred(Job๊ณผ ๋์ผํจ์ ๊ธฐ์ต)๋ start, join, await๋ฅผ ํธ์ถํ ๋ active ์ํ๋ก ๋ณ๊ฒฝ๋๋ค. active ์์ ์ ์ง์ ๊ฒฐ์ ํ ์ ์๋ค๋ ๊ฒ์ด ํฐ ์ฅ์ ์ด๋ค. by lazy๋ก ์ฒ์ ์ฌ์ฉํ ๋ ์ด๊ธฐํ๋๋ ๊ฒ๊ณผ ๊ฐ์ด ์๋ํ๋ ๊ฒ์ผ๋ก ์ดํดํ๋ฉด ๋ ๊ฒ ๊ฐ๋ค.
LAZY๋ฅผ ์ฌ์ฉํ๊ณ ์ํ๊ณ ์ ์คํ์๊ฐ ์ฐจ์ด๋ ๊ฑฐ์ ์๋ค. ๊ทธ๋ฌ๋ new์ํ๋ก ๋๋ฉด ์ฌ์ฉ์ด ๋ถ๊ฐ๋ฅํ๊ณ start, join, await๋ฅผ ํธ์ถํด active์ํ๋ก ๋ฐ๊ฟ์ฃผ๋ฉด ์ฌ์ฉ๊ฐ๋ฅํ๋ค. ๋ค๋ง ์กฐ์ฌํด์ผ๋ ๊ฒ์ await๋ ์ฝ๋ฃจํด์ ์คํํ๊ณ ์ข ๋ฃ๋๋ ๊ฒ๊น์ง ํฌํจํ๋ ํจ์์ด๊ธฐ ๋๋ฌธ์ ๋ฏธ๋ฆฌ active๋ก ๋ฐ๊พธ์ง์์ผ๋ฉด ์์ ๊ฐ์ ์ํฉ์์๋ ์์ฐจ์คํ๊ณผ ์์ ํ ๋์ผํ ์ํฉ์ด ๋๋ค.
Global scope
๊ธ๋ก๋ฒ ์ค์ฝํ๋ฅผ ์ด์ฉํ๋ฉด suspend ๋ฅผ ์๋ถ์ด๊ณ ๋ suspend fun์ ๋ง๋ค ์ ์๋ค. @OptIn ์ด๋ ธํ ์ด์ ์ด ํ์ํ์ง๋ง ์ด๋ ๊ฒ ํ๋ฉด ์ฝ๋ฃจํด ๋ฐ์์ ์ด ํจ์๋ฅผ ์คํํ ์ ์๊ฒ ๋๋ค.
// The result type of somethingUsefulOneAsync is Deferred<Int>
@OptIn(DelicateCoroutinesApi::class)
fun somethingUsefulOneAsync() = GlobalScope.async {
doSomethingUsefulOne()
}
์คํ์๊ฐ์ผ๋ก ๋ณด๋ฉด ๊ทธ๋ฅ ์ฝ๋ฃจํด์ค์ฝํ ๋ด์์ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค 100ms ๋ ๋๋ฆฌ๋ค.
๊ธ๋ก๋ฒ ์ค์ฝํ๋ ์ฑ ์๋ช ์ฃผ๊ธฐ ์ ์ฒด์ ์กด์ฌํ๊ณ ์ทจ์์ํฌ ์ ์๋ค. ์ด๋ฐ ํํ๋ ๋ฉ๋ชจ๋ฆฌ ๋์์ ๊ฐ์ ์๊ธฐ์น ๋ชปํ ์ค๋ฅ๋ฅผ ๋ผ ๊ฐ๋ฅ์ฑ์ด ์๋๋ฐ ์ด๊ฑด structured concurrency๋ก ํด๊ฒฐํ ์ ์๋ค.
structured concurrency
์ฝ๋ฃจํด์ ์ ์ผ ํฐ ๊ฐ๋ ์ธ structured concurrency์ด๋ค. ์์ ์ฝ๋ฃจํด์ด ๋ถ๋ชจ ์ฝ๋ฃจํด์์์ ์กด์ฌํ๊ณ , ์์์ฝ๋ฃจํด์์ ์๊ฒจ๋ ์์ธ๊ฐ ๋ถ๋ชจ๊น์ง ์ ํ๋๋ ํ์์ ์ด์ผ๊ธฐํ๋ฉฐ ์ค์ฝํ ์์์ ๋ค๋ฃจ๊ธฐ๋๋ฌธ์ ๋ณ์๋ฅผ ํต์ ํ ์ ์๋ค.
์ง๊ธ๊น์ง ์ ์๋ ์ฝ๋๋ฅผ ํจ์ํ ์์ผ์ ์ฌ์ฉํ๋ ๊ฒ์ธ๋ฐ one.await()+two.await()๋ถ๋ถ๊น์ง ํจ์๋ก ๋ฝ๋ ๊ฒ์ด๋ค.
suspend fun concurrentSum(): Int = coroutineScope {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
one.await() + two.await()
}
val time = measureTimeMillis {
println("The answer is ${concurrentSum()}")
}
suspend fun ํ๋๋ฅผ ๋ฑ ํธ์ถํ๋ ๊ฒ์ผ๋ก ์ ๊ณผ์ ์ ๋ค ์ ๋ฆฌํ ์ ์๋ค. ์ด ๊ณผ์ ์์ exception๋ ๋ค ์ ํ๋๋ค.
"๋๊ธ, ๊ณต๊ฐ ๋ฒํผ ํ ๋ฒ์ฉ ๋๋ฅด๊ณ ๊ฐ์ฃผ์๋ฉด ํฐ ํ์ด ๋ฉ๋๋ค"
'Android ๐ฅ๏ธ > Coroutine๐' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Coroutine exceptions handling (0) | 2024.03.29 |
---|---|
Asynchronous Flow - Intermediate flow operators~ (1) | 2024.03.29 |
Coroutine context and dispatchers (0) | 2024.03.29 |
Coroutine Cancellation and timeouts (0) | 2024.03.29 |
Coroutines basics - runBlocking, launch, job, coroutineScope (0) | 2024.03.29 |