π‘ μ€μ μ½λ£¨ν΄ λ΄λΆκ° μ΄λ»κ² μλνλμ§ μ΄ν΄νκΈ° μν νμ΅μ λλ€.
μ½λ£¨ν΄μ μ€μ ꡬν?
- μ€λ¨ ν¨μλ ν¨μκ° μμν λμ μ€λ¨ ν¨μκ° νΈμΆλμμ λ μνλ₯Ό κ°μ§λ€λ μ μμ μν λ¨Έμ (state machine)κ³Ό λΉμ·ν©λλ€.
- *state machine : νλμ μνλ§μ κ°μ§λ μΆμ κΈ°κ³
- 컨ν°λ΄μμ΄μ
(continuation) κ°μ²΄λ μνλ₯Ό λνλ΄λ μ«μμ λ‘컬 λ°μ΄ν°λ₯Ό κ°μ§κ³ μμ΅λλ€.
- ν¨μμ 컨ν°λ΄μμ΄μ κ°μ²΄κ° μ΄ ν¨μλ₯Ό λΆλ₯΄λ λ€λ₯Έ ν¨μμ 컨ν°λ΄μμ΄μ κ°μ²΄λ₯Ό μ₯μ(Decorate)μ΄λΌκ³ ν©λλ€.
- 컨ν°λ΄μμ΄μ κ°μ²΄λ μ€νμ μ¬κ°νκ±°λ μ¬κ°λ ν¨μλ₯Ό μλ£ν λ μ¬μ©λλ μ½ μ€νμΌλ‘ μ¬μ©λ©λλ€.
컨ν°λ΄μμ΄μ μ λ¬ λ°©μ (CPS)
- continuation-passing style
- νλ‘κ·Έλ¨μ νλ¦μ μ μ΄νκΈ° μν΄ continuationλ₯Ό λͺ μμ μΌλ‘ μ λ¬νλ μ€νμΌμ΄λ©°, νλ‘κ·Έλ¨μ νμ¬ μνλ₯Ό λνλ΄λ κ°μ²΄μΈ continuationμ λ€μ ν¨μ νΈμΆμ μ λ¬νμ¬ μ μ΄ νλ¦μ μ μ§ν©λλ€.
- ν¨μμμ ν¨μλ‘ μΈμλ₯Ό ν΅ν΄ μ λ¬λλ©°, λ§μ§λ§ νλΌλ―Ένλ‘ μ λ¬λ©λλ€.
suspend fun getUser() : User?
// λ΄λΆλ..
fun getUser(continuation: Continuation<*>): Any
- Nullable ννλ‘ λ°λ μ΄μ λ, μ€λ¨ ν¨μλ₯Ό μ€ννλ λμ€μ μ€λ¨λλ©΄ μ μΈλ νμ μ κ°μ λ°ννμ§ μμ μλ μκΈ° λλ¬Έμ λλ€.
- κ° ν¨μλ μμ λ§μ 컨ν°λ΄μμ΄μ κ°μ²΄λ₯Ό νμλ‘ ν©λλ€.
μΌλ°μ μΈ λΉλκΈ° μμ with asyncTask
fun main() {
println("Before")
asyncTask {
println("After")
}
}
fun asyncTask(callback: () -> Unit) {
Thread.sleep(1000) // delay
callback()
}
- μ μ½λμμλ asyncTaskκ° μλ£λ νμ μ½λ°±μ νΈμΆν©λλ€.
- ν΄λΉ μμ μ CPS(continuation-passing style)λ‘ μμ νλ©΄ μλμ κ°μ΅λλ€.
fun main() {
println("Before")
asyncTask(::afterTask)
}
fun asyncTask(continuation: () -> Unit) {
Thread.sleep(1000) // delay
continuation()
}
fun afterTask() {
println("After")
}
- μ¬κΈ°μ asyncTaskλ μμ μ΄ μλ£λ ν νΈμΆν continuationμ μΈμλ‘ λ°μΌλ©°, continuationλ μμ μ΄ μλ£λλ©΄ νΈμΆλ©λλ€.
μ½νλ¦° μ½λ£¨ν΄μμλ?
- μ½νλ¦° μ½λ£¨ν΄μμλ μ΄ κ°λ μ΄ μ€λ¨μ μ¬κ°ν μ μκ² νλ λ΄λΆ λ©μ»€λμ¦μΌλ‘ μ¬μ©λ©λλ€.
- suspend ν¨μλ₯Ό νμ©νμ¬ λ΄λΆμ μΌλ‘ continuationμ μ¬μ©νμ¬ μ½λ£¨ν΄μ μ€λ¨ μ§μ μ κ΄λ¦¬ν©λλ€.
fun main() {
val continuation = suspendAndSetContinuation()
continuation.resume(Unit)
println("After resuming")
}
suspend fun suspendAndSetContinuation(): Continuation<Unit> {
return suspendCoroutine { cont ->
println("Before suspending")
cont // Return the continuation to the caller
}
}
μνλ₯Ό κ°μ§ ν¨μ
- ν¨μκ° μ€λ¨λ νμ λ€μ μ¬μ©ν μ§μ λ³μλ νλΌλ―Έν°μ κ°μ μνλ₯Ό κ°μ§κ³ μλ€λ©΄, ν¨μμ 컨ν°λ΄μμ΄μ κ°μ²΄μ μνλ₯Ό μ μ₯ν΄μΌ ν©λλ€.
suspend fun myFunction() {
println("Before")
var counter = 0
delay(1000) //μ€λ¨ ν¨μ
counter++
println("Counter: $counter")
println("After")
}
- counterλ 0κ³Ό 1λ‘ νμλ λ μνλ₯Ό κ°μ§κ² λ©λλ€.
- μ΄ λ 컨ν°λ΄μμ΄μ κ°μ²΄λ₯Ό ν΅ν΄μ μ΄λ₯Ό μ λ¬ν΄μΌνλ©°, μ€λ¨λκΈ° μ μ κ°μ μ μ₯νκ³ μ¬κ°λ λ 볡ꡬλ©λλ€.
κ°μ λ°μ μ¬κ°λλ ν¨μ
- μ€λ¨ ν¨μλ‘λΆν° κ°μ λ°μμΌνλ κ²½μ°λ₯Ό μ΄ν΄λ³΄κ² μ΅λλ€.
suspend fun printUser(token: String) {
println("Before")
val userId = getUserId(token) // μ€λ¨ ν¨μ
println("Got UserId: $userId")
val userName = getUserName(userId, token) //μ€λ¨ ν¨μ
println(User(userId,userName))
println("After")
}
- λ κ°μ§ μ€λ¨ ν¨μκ° μμΌλ©° μλμ κ°μ μ μ½μ¬νμ΄ μμ΅λλ€.
- tokenμ΄λΌλ νλΌλ―Έν°λ₯Ό λ°μΌλ©΄ μ€λ¨ ν¨μλ νΉμ κ°μ λ°νν΄μΌ νλ€.
- νλΌλ―Έν°μ λ°νκ° λͺ¨λ 컨ν°λ΄μμ΄μ κ°μ²΄μ μ μ₯λμ΄μΌ νλ€.
- ν¨μκ° κ°μΌλ‘ μ¬κ°λμλ€λ©΄ κ²°κ³Όλ Result.Success(value)κ° λ©λλ€.
- λ°λ©΄μ μμΈλ‘ μ¬κ°λμλ€λ©΄ κ²°κ³Όλ Result.Failure(exception)μ΄ λλ©° μμΈλ₯Ό λμ§λλ€.
μ½ μ€ν(call stack)
- ν¨μ aκ° ν¨μ bλ₯Ό νΈμΆνλ©΄ κ°μ λ¨Έμ μ aμ μνμ bκ° λλλ©΄ μ€νμ΄ λ μ§μ μ μ΄λκ°μ μ μ₯ν΄μΌ ν©λλ€.
- μ΄λ₯Ό μ½λ£¨ν΄μμλ μ½ μ€ν(call stack)μ΄λΌλ μλ£κ΅¬μ‘°μ μ μ₯νλ©°, μ½λ£¨ν΄μ μ€λ¨νλ©΄ μ€λ λλ₯Ό λ°νν΄ μ½ μ€νμ μλ μ 보λ₯Ό μ κ±°ν©λλ€.
- μ½λ£¨ν΄μ μ¬κ°ν λ μ½ μ€νμ μ¬μ©ν μμμΌλ―λ‘, 컨ν°λ΄μμ΄μ κ°μ²΄κ° μ½ μ€νμ μν μ λμ ν©λλ€.
- λ°λΌμ 컨ν°λ΄μμ΄μ
κ°μ²΄λ μλμ κ°μ μ 보λ₯Ό κ°μ§λλ€.
- μ€λ¨ λμμ λμ μν(label)
- μ§μ λ³μμ νλΌλ―Έν°(νλ)
- μ€λ¨ ν¨μλ₯Ό νΈμΆν ν¨μκ° μ¬κ°λ μμΉ μ 보
컨ν°λ΄μμ΄μ κ°μ²΄μ μ°Έμ‘°
- νλμ 컨ν°λ΄μμ΄μ κ°μ²΄κ° λ€λ₯Έ νλλ₯Ό μ°Έμ‘°νκ³ , μ°Έμ‘°λ κ°μ²΄κ° λλ€λ₯Έ 컨ν°λ΄μμ΄μ κ°μ²΄λ₯Ό μ°Έμ‘°ν©λλ€.
- μ΄ λλ¬Έμ 컨ν°λ΄μμ΄μ κ°μ²΄λ κ±°λν μνμ κ°μΌλ©°, μΌλ°μ μΌλ‘ μ½ μ€νμ μ μ₯λλ μ 보λ₯Ό λͺ¨λ κ°μ§κ³ μμ΅λλ€.
컨ν°λ΄μμ΄μ κ°μ²΄μ λμ μμ
- 컨ν°λ΄μμ΄μ κ°μ²΄κ° μ¬κ°λ λ κ° μ»¨ν°λ΄μμ΄μ κ°μ²΄λ μμ μ΄ λ΄λΉνλ ν¨μλ₯Ό λ¨Όμ νΈμΆν©λλ€.
- ν¨μμ μ€νμ΄ λλλ©΄ μμ μ΄ νΈμΆν ν¨μμ 컨ν°λ΄μμ΄μ μ μ¬κ°ν©λλ€.
- μ¬κ°λ 컨ν°λ΄μμ΄μ κ°μ²΄ λν λ΄λΉνλ ν¨μλ₯Ό νΈμΆν©λλ€.
- μ΄ κ³Όμ μ μ€νμ λμ λ€λ€λ₯Ό λκΉμ§ λ°λ³΅ν©λλ€.
override fun resumeWith(result: Result<String>) {
this.result = result
val res = try {
val r = printUser(token,this)
if (r == COROUTINE_SUSPENDED) return
Result.success(r as Unit)
} catch(e: Throwable) {
Result.failure(e)
}
completion.resumeWith(res)
}
- ν¨μ aκ° ν¨μ bλ₯Ό νΈμΆνκ³ , ν¨μ bλ ν¨μ cλ₯Ό νΈμΆν λ, ν¨μ cμμ μ€λ¨λ μν©μ νμΈν΄λ³΄κ² μ΅λλ€.
- μ€νμ΄ μ¬κ°λλ©΄ cμ 컨ν°λ΄μμ΄μ κ°μ²΄λ c ν¨μλ₯Ό λ¨Όμ μ¬κ°ν©λλ€.
- a() → b() → c()μμ μ€λ¨λλ€λ©΄, c() μ¬κ° → b() μ¬κ° → a() μ¬κ° μμΌλ‘ λμν©λλ€.
μμΈ μν©μμλ?
- μμΈλ₯Ό λμ§ λλ μ΄μ λΉμ·νκ² λμν©λλ€.
- resumeWithμμ μ‘νλ©΄ Result.failure(e)λ‘ λνλλ©°, μμΈλ₯Ό λμ§ ν¨μλ₯Ό νΈμΆν ν¨μλ ν¬μ₯λ κ²°κ³Όλ₯Ό λ°μ μ μμ΅λλ€.
- μ€λ¨λ ν¨μκ° μ¬κ°νμ λ 컨ν°λ΄μμ΄μ κ°μ²΄λ‘λΆν° μνλ₯Ό 볡μνκ³ , μ»μ κ²°κ³Όλ₯Ό μ¬μ©νκ±°λ μμΈλ₯Ό λμ ΈμΌ ν©λλ€.
μ€μ μ½λ£¨ν΄ μ½λ
- 컨ν°λ΄μμ΄μ
κ°μ²΄μ μ€λ¨ ν¨μλ₯Ό μ»΄νμΌν μ€μ μ½λλ μ΅μ νλμ΄ μμΌλ©°, μλμ κ°μ λͺ κ°μ§ μ²λ¦¬ κ³Όμ μ΄ λ ν¬ν¨λμ΄ μμ΅λλ€.
- μμΈκ° λ°μνμ λ λ λμ μ€ν νΈλ μ΄μ€ μμ±
- μ½λ£¨ν΄ μ€λ¨ μΈν°μ μ
- μ¬μ©νμ§ μλ λ³μλ₯Ό μ κ±°νκ±°λ, ν μΌμ½ μ΅μ
- tail-call : ν¨μλ₯Ό νΈμΆνμ¬ κ°μ λ°νλ°μ λ€ μ΄λ ν νμ²λ¦¬ μμ΄ κ·Έλλ‘ λ°ννλ λ°©μ
- tail-call optimization : ν μΌμ½λ‘ μ§μ¬μ§ μ½λμμ ν μ΄μ½λ‘ νΈμΆνλ ν¨μμ λν μ€νμ λ§λ€μ§ μκ³ , ν¨μκ° λ°νν κ°μ λμ μ¬μ©νμ¬ μ€νμ μ΅μνμΌλ‘ λ§λλ μ΅μ ν λ°©μ
μ€λ¨ ν¨μμ μ±λ₯
- μ½λ£¨ν΄ λ΄λΆ ꡬνμ λ³Έλ€λ©΄ λλΆλΆμ μ¬λλ€μ΄ λΉμ©μ΄ ν΄ κ²μ΄λΌκ³ μκ°νμ§λ§, μ€μ λ‘λ κ·Έλ μ§ μμ΅λλ€ !
- ν¨μλ₯Ό μνλ‘ λλλ κ²μ λΉμ©μ΄ κ±°μ μμΌλ©°, κ°λ¨ν λ°©μμ νμ©ν©λλ€.
- Rxjavaλ μ½λ°± ν¨μμ μ±λ₯κ³Ό λΉκ΅νμ λ ν° λΉμ©μ μꡬνμ§ μμ΅λλ€.
μμ½
- μ€λ¨ ν¨μλ μν λ¨Έμ κ³Ό λΉμ·νλ©°, ν¨μκ° μμλ λμ μ€λ¨ ν¨μλ₯Ό νΈμΆν λ€μ μνλ₯Ό κ°μ§λλ€.
- μνλ₯Ό λνλ΄λ κ°κ³Ό λ‘컬 λ°μ΄ν°λ 컨ν°λ΄μμ΄μ κ°μ²΄μ μ μ₯λ©λλ€.
- νΈμΆν ν¨μμ 컨ν°λ΄μμ΄μ κ°μ²΄λ ν¨μκ° μ¬κ°λ λ λλ μ¬κ°λ ν¨μκ° μλ£λ λ μ¬μ©λλ μ½ μ€νμ μν μ ν©λλ€.
https://m.yes24.com/Goods/Detail/123034354