๋ณธ ๊ฒ์๊ธ์ Coroutine ๊ฐ๋
์ Android ๋ด์์ ์ฌ์ฉ๋๋ ๊ฒ์ ์ ์ ๋ก ์์ฑ๋์๋ค.
#1 ์ด์ ๊ธ
[Kotlin] Coroutines - ๋๊ธฐ ์ฝ๋, ๋น๋๊ธฐ ์ฝ๋
#1 ๋๊ธฐ ์ฝ๋ vs ๋น๋๊ธฐ ์ฝ๋ #1-1 ๊ตฌ๋ถํ๊ธฐ ์ฝ๋ฃจํด์ ์ ๋๋ก ์ฌ์ฉํ๊ธฐ ์ํด์ ๋จผ์ , '๋๊ธฐ ์ฝ๋'์ '๋น๋๊ธฐ ์ฝ๋(= ์ฝ๋ฃจํด ์ฝ๋)'๋ฅผ ๋ช ํํ๊ฒ ๊ตฌ๋ถํ ์ค ์์์ผ ํ๋ค. ๋์ ๊ตฌ๋ถํ๋ ๊ธฐ์ค์ ์ฝ๊ฒ ๋ง
kenel.tistory.com
ํด๋น ๊ฒ์๊ธ์ ์ฝ์ด์ผ ๋ณธ ๊ฒ์๊ธ์ ์ดํดํ ์ ์๋ค.
#2 suspend ํค์๋
#2-1 suspend์ resume
๋น๋๊ธฐ ์ฝ๋, ์ฆ ์ฝ๋ฃจํด์ suspend(๊ธฐ๋ค๋ฆผ)์ด ํ์ํ ์ฝ๋๋ค. ๊ธฐ๋ค๋ฆผ์ด ์๋ค๋ ๊ฑด resume(๋ค์ ์์ง์, ์ฌ๊ฐ)๋ ์๋ค๋ ๋ง์ด๋ค. ์ฝ๋ฃจํด์ ๊ธฐ๋ค๋ฆฌ๊ฒ(suspend) ๋ง๋ค๋ฉด, ํด๋น ์ฝ๋ฃจํด์ ์คํ ํ๋ ์์ด ๋ณต์ฌ๋์ด ๋ณ๋๋ก ์ ์ฅ๋๋ค. ๊ทธ๋ฆฌ๊ณ ํด๋น ์ฝ๋ฃจํด์ ์ฌ๊ฐ(resume)์ํค๋ฉด, ์คํ ํ๋ ์์ ๋ค์ ๋ถ๋ฌ์ค๊ณ ๊ทธ ์คํ ํ๋ ์์ด ์ ์ฅ๋์๋ ๊ณณ์์ ์ฝ๋ฃจํด์ด ๋ค์ ์์๋๋ค.
#2-2 ๊ธฐ๋ณธ Suspending Function
์ค๋ ๋๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ฒ ๋ง๋๋ ํจ์ ์ฆ 'Suspending Function'์ ๋ค์๊ณผ ๊ฐ๋ค.
coroutineScope()
supervisorScope()
delay()
join()
await()
receive()
withContext()
withTimeout()
withTimeoutOrNull()
์ด ํจ์๋ค์ ์ฝ๋ฃจํด ๊ธฐ๋ณธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(kotlinx.coroutines)์ Suspending Function๋ค์ด๋ค. ์ด ๊ธฐ๋ณธ ํจ์๋ค์ #2-3์ ๋ฌ๋ฆฌ ์์์ ์ผ๋ก suspend ํค์๋๊ฐ ์ ์ฉ๋์ด์ ธ ์๋ค. ์ฌ๋ด์ผ๋ก, Room์ด๋ Retrofit๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๊ธฐ๋ณธ Suspending Fuction๋ค์ ์ถ๊ฐ๋ก ์ ๊ณตํด์ค๋ค๊ณ ํ๋ค.
์ฌ๋ด์ผ๋ก, runBlocking์ ๊ธฐ๋ค๋ฆฌ๊ฒ(Suspend) ๋ง๋ค์ง ์๊ณ , ๋ฉ์ถ๊ฒ(Block) ๋ง๋๋ ๊ฒ์ด๋ฏ๋ก, ์ ๋ช
๋จ์ ์๋ค. ๊ทธ๋ฐ๋ฐ ๊ทธ ์ ์, runBlocking์ ์ ์ด์ ๋๊ธฐ ์ฝ๋๋ผ์ ๋๋์ฑ ๋ช
๋จ์ ์ค๋ฅผ ์ ์๋ค.
#2-3 ์ฌ์ฉ์ ์ ์ Suspending Function
import kotlinx.coroutines.*
suspend fun suspendingFunction() {
println("suspendingFunction() called")
delay(1000) // 1์ด ๋๊ธฐ
}
fun main() {
println("Start")
runBlocking {
suspendFunction()
}
println("End")
}
/* ์ถ๋ ฅ ๊ฒฐ๊ณผ
Start
suspendingFunction() called
End
*/
์ฌ์ฉ์ ์ ์ ํจ์๋ฅผ Suspending Function์ผ๋ก ๋ง๋ค ์๋ ์๋๋ฐ, #2-2์ ๋ฌ๋ฆฌ ๋ช
์์ ์ผ๋ก suspend ํค์๋๋ฅผ ์ ์ด์ผ ํ๋ค. ํจ์ ํค์๋์ธ fun ์์ suspend ํค์๋๋ฅผ ๋ถ์ฌ์ฃผ๋ฉด ๋๋ค.
#2-4 Suspending Function์ ์ ์ฝ
#2-2 ๋๋ #2-3์ Suspending Function์ ๋น๋๊ธฐ ์ฝ๋์ ์์ญ(์ด ๋งํฌ์ #2 ์ฐธ์กฐ)์ด ๋๋ฉฐ, ๊ทธ ์์ญ ์์์ Suspend Function์ ๋น๋กฏํ ์ฝ๋ฃจํด API ์ฝ๋๋ฅผ ๋ง์๊ป ์ฌ์ฉํ ์ ์๋ค. ํ์ง๋ง ์ ์ฝ๋ ์๊ธด๋ค. ์์ผ๋ก ํด๋น ํจ์๋ ๋๊ธฐ ์ฝ๋์ ์์ญ(์ด ๋งํฌ์ #2 ์ฐธ์กฐ)์์ ํธ์ถํ ์ ์๋ค. ๋๊ธฐ ์ฝ๋์ ๋น๋๊ธฐ ์ฝ๋์ ์์ญ์ ๊ตฌ๋ถํ๋ ํฌ์ฅ์ง ์ญํ ์ธ CoroutineScope ๋ฑ์ ์ ์ธํ๋ฉด, Suspend ํจ์๋ ์ค์ง Suspend ํจ์ ๋ด์์๋ง ํธ์ถํ ์ ์๋ค.
#3 suspend ํค์๋์ ์๋ ๊ธฐ์
#3-1 ์ํ ์ฝํ๋ฆฐ ํด๋์ค
// package com.example.coroutinesbasics
import kotlinx.coroutines.delay
class SuspendPractice {
fun normalFunction() {
println("This is normalFunction")
}
suspend fun suspendingFunction() {
println("This is suspendingFunction")
delay(1000)
}
}
์ด ์ฝํ๋ฆฐ ํด๋์ค๋ฅผ ์ด์ฉํด suspend ํค์๋๊ฐ ์๋ํ๋ ๋ด๋ถ์ ์ธ ๊ธฐ์ ๋ฅผ ์ดํด๋ณธ๋ค.
#3-2 Bytecode ์์ฑ
suspend ํค์๋์ ์๋ ๊ธฐ์ ๋ฅผ ์ดํด๋ณด๊ธฐ ์ํด์, ๋จผ์ #3-1์ ์ํ ์ฝํ๋ฆฐ ํด๋์ค๊ฐ Bytecode๋ฅผ ์์ฑํ๋๋ก ๋น๋์ํจ๋ค. [Build] - [Rebuild Project]๋ฅผ ํด๋ฆญํ๋ค.
[Tools] - [Kotlin] - [Show Kotlin Bytecode]๋ก ์์ฑํ๋ Kotlin Bytecode๋ฅผ ๋ณธ๋ค
#3-3 Decompile
#3-2๋ฅผ ํตํด ์ฐ Kotlin Bytecode๋ฅผ ์ฐ๋ฆฌ๊ฐ ์ฝ์ ์ ์๋ ํํ๋ก ๋ณํํด์ผ ํ๋ค. Decompile ๋ฒํผ์ ํด๋ฆญํ๋ค.
// package com.example.coroutinesbasics;
import kotlin.Metadata;
import kotlin.Unit;
import kotlin.coroutines.Continuation;
import kotlin.coroutines.intrinsics.IntrinsicsKt;
import kotlinx.coroutines.DelayKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@Metadata(
mv = {1, 9, 0},
k = 1,
d1 = {"\u0000\u0014\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0002\b\u0003\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u0006\u0010\u0003\u001a\u00020\u0004J\u0011\u0010\u0005\u001a\u00020\u0004H\u0086@ø\u0001\u0000¢\u0006\u0002\u0010\u0006\u0082\u0002\u0004\n\u0002\b\u0019¨\u0006\u0007"},
d2 = {"Lcom/example/coroutinesbasics/SuspendPractice;", "", "()V", "normalFunction", "", "suspendingFunction", "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", "app_debug"}
)
public final class SuspendPractice {
public final void normalFunction() {
String var1 = "This is normalFunction";
System.out.println(var1);
}
@Nullable
public final Object suspendingFunction(@NotNull Continuation $completion) {
String var2 = "This is suspendingFunction";
System.out.println(var2);
Object var10000 = DelayKt.delay(1000L, $completion);
return var10000 == IntrinsicsKt.getCOROUTINE_SUSPENDED() ? var10000 : Unit.INSTANCE;
}
}
Decompile ๋ฒํผ์ ๋๋ฅด๋ฉด ์์ ๊ฐ์ SuspendPractice.decompiled.java ํ์ผ์ด ๋ง๋ค์ด์ง๋ค. ์ด ํ์ผ์ ์ฐ๋ฆฌ๊ฐ SuspendPractice.kt๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์์ฑํ๋ ์ฝํ๋ฆฐ ๋ฐ์ดํธ์ฝ๋๋ฅผ Java ์ธ์ด๋ก ํด์(Interpretation)ํ ๊ฒ์ด๋ค. suspend ํจ์์ Continuation ํ์
์ ๋งค๊ฐ๋ณ์๊ฐ ๋ค์ด๊ฐ ์๋ ๊ฒ์ด ๋ณด์ธ๋ค. Continuation ์ธํฐํ์ด์ค๋ ์ฝ๋ฃจํด ์ฝ๋๊ฐ suspend(์ผ์ ์ ์ง)๋์๋ค๊ฐ ๋์ค์ ๋ค์ resume(์ฌ๊ฐ)๋ ๋์ ๋์์ ๊ด๋ฆฌํ๋ค. ๋จ์ด์ ๋ป์ฒ๋ผ ๋ง ๊ทธ๋๋ก ์ฐ์(Continuation)์ ๊ด๋ฆฌ๋ค.
#4 ์์ฝ
suspend ํค์๋๋ ํด๋น ํจ์๊ฐ ๋น๋๊ธฐ ์ฝ๋์ ์์ญ์์ ๋ช ์์ ์ผ๋ก ํ์ํ๋ค. ํ๋ก๊ทธ๋๋จธ์๊ฒ ๊ทธ๋ฆฌ๊ณ ์ปดํ์ผ๋ฌ์๊ฒ.
'๊นจ์ ๊ฐ๋ ๐ > Kotlin' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Kotlin] Coroutines - Structured Concurrency (0) | 2024.02.16 |
---|---|
[Kotlin] Couroutine - ์ค๋ ๋(Thread)์ ์ค๋ ๋ ํ(Thread Pool) (1) | 2024.02.15 |
[Kotlin] Coroutines - runBlocking (0) | 2024.02.13 |
[Kotlin] Coroutines - Coroutine builder (0) | 2024.02.12 |
[Kotlin] Coroutines - CoroutineScope, CoroutineContext (1) | 2024.02.10 |