본문 바로가기
프로그래밍 놀이터/Kotlin

[Kotlin] Coroutine vs. thread (Light-weight thread 가 뭔 말이야?)

by 돼지왕왕돼지 2018. 11. 26.

[Kotlin] Coroutine vs. thread (Light-weight thread 가 뭔 말이야?)


https://stackoverflow.com/questions/43021816/difference-between-thread-and-coroutine-in-kotlin


buildSequence, concurrency, concurrent vs parallel, context change, Continuation, cooperatively, coroutine, coroutine builder, coroutine 용어 정리, Future, kotlin stackless coroutine, launch, light weight thread, linux thread limit, mac os process thread limit, preemptively, Scheduling, stackful, stackless, stackless coroutine, suspend modifier, suspended, suspending function, Suspending function type, Suspending lambda, Suspension point, switch 명시, thread, thread stack, thread vs coroutine, [Kotlin] Coroutine vs. thread (Light-weight thread 가 뭔 말이야?)


-

Coroutine 은 stackless, stackful 이렇게 두 가지 type 이 있다.

Kotlin 은 stackless coroutine 이다. stackless 이기 떄문에 약간의 기능제한이 있다.



-

https://www.quora.com/Why-is-it-that-with-a-stackless-coroutine-only-the-top-level-routine-may-be-suspended


Stackless coroutine 은 caller 에게 항상 무엇인가를 return 한다.

result 또는 “no result yet, I’m suspended”. 둘 중 하나이다.

Caller 는 이 2가지 형태의 return 에 대해서 대처를 해야 한다.

Caller 자체도 stackless coroutine 이라면 바로 또 다시 그의 caller 에게 값을 전달한다.

stackless coroutine 은 “resumable functions” 라고 불린다.


Stackful coroutine 은 완벽하게 일반적인 function 과 같다.

stack(caller 의 local variable 등) 과 함께 스스로 suspend 할 수도 있고, 값을 return 할 수도 있다. 일반적인 thread 같이 말이다.

그리고 scheduler 에게 다른 suspended stackful coroutine 을 수행하게 할 수 있다.

stackful coroutine 은 “cooperative multitasking” 이라고 불린다.


정리하면 

stackless coroutine 은 control 을 위로(caller 에게) 보내고,

stackfull coroutine 은 control 을 아래로 보낸다고 보면 된다.



-

Stackless : C#, Scala, Kotlin

Stackful : Quasar, Javaflow



-

light-weight thread 라는 의미는..

coroutine 이 자신만의 stack 을 갖지 않는다는 의미이다.

native thread 와 mapping 이 되는 것이 아니며, context switching 등이 일어나지 않는다.



-

Thread 는 OS 에 의해 관리되며, preemptively(선매하여, 우선적으로) multitasking 이다.

Coroutine 은 User 에 의해 관리되며, cooperatively(협력하여, 협조적으로) multitasking 이다.



-

for(i in 0..10_0000){

    async(CommonPool){

        delay(1)

        println(i)

    }

}

위 코드는 2 * 10_0000 Continuation instance 를 만든다.


val job = async(CommonPool){

    for(i in 0..10_0000){

        delay(1)

        println(i)

    }

}

job.join()


이 경우 10_0001 개의 Continuation 을 만든다.



-

https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md


Coroutine

    suspendable computation instance

    thread 와 비슷하다. code 를 가지고 있고 수행되며 life cycle 이 있다.

    그러나 실제 특정 thread 에 bound 되지 않는다.

    한 thread 에서 실행되었다가 suspend 되고, 다른 thread 에서 resume 될 수 있다.

    Future 와 같이 result 를 return 하면서 혹은 exception 을 던지면서 complete 될 수 있다



Suspending function

    suspend 로 마킹되어 있는 녀석.

    다른 suspend function 을 호출하면서 현재 thread 를 blocking 하지 않으면서 실행을 suspend 시킬 수 있다.

    suspending function 은 일반 code 에서 호출할 수 없다. 오직 다른 suspending function 또는 suspending lambda 에서 호출할 수 있다.



Suspending lambda

    coroutine 에서 수행되어야 하는 code block.

    일반적인 lambda 와 비슷하지만, functional type 은 suspend modifier 를 가지고 있다.

    anonymous suspending function 의 short syntactic form 이다.

    launch, future, buildSequence 등에 suspending lambda 를 쓸 수 있다.



Suspending function type

    일반적인 function type 과 같지만 suspend modifier 가 있다.

    suspend () -> Int 가 그 예이다.

    suspend fun foo() : Int 도 그 예이다.



Coroutine builder

    suspending lambda 를 argument 로 받아서 coroutine 을 만드는 function.

    launch, future, buildSequence 등이 그 예이다.



Suspension point

    Coroutine 실행 중에 suspend 되는 point 를 이야기한다.

    보통 suspending function 을 호출하는 지점이다.



Continuation

    suspension point 에서의 coroutine state 를 이야기한다.    

    buildSequence{

        for(i in 1..10) yield(i * i)

        println(“over”)

    } 


    여기에서 yield() 를 호출할 때마다 coroutine 은 suspend 된다.

    나머지 수행이 continuation 이라 불린다.

    여기에서는 10개의 continuation 을 갖는다.

    coroutine 이 생성되었지만 start 되지 않은것이 initial continuation 이라 불리며 Continuation<Unit> type 이다.



-

https://stackoverflow.com/questions/1934715/difference-between-a-coroutine-and-a-thread


thread 는 stack 을 가지며 보통 1MB 사이즈를 갖는다.

64k 가 JVM 에서 thread 에 할당하는 최소 사이즈이다.

stack 을 가지고 있어 context-switching 에 cost 더 더 든다.



-

Mac OS 의 경우 process 당 2000 thread 까지 생성 가능하다.

Linux 는 thread 당 8MB stack 을 주고, 물리적 RAM 이 감당하는 수준까지 thread 를 만들 수 있다.



-

Coroutine 은 concurrent 하게 수행되지만 절대 parallel 로 실행되지 않는다.

coroutine 은 overhead(context-switching, scheduling) 가 없는 concurrency 를 제공한다.



-

Coroutine 은 언제 switch 가 되어야하는지 “반드시” 명시해주어야 한다.

반면에 thread 는 OS 가 알아서 switch 시점을 잡아 수행한다.



-

Concurrent : 두개 이상의 계산이 한 time frame 에 동시에 “존재"하고, 둘 사이에 dependency 가 있다. 실제 수행은 one by one 이다.

Parallel : 2개 이상의 계산이 "동시에" 이루어진다.




댓글0